From 09988cb7675d8d5b5058d3d56c76b7ccdd77f0ed Mon Sep 17 00:00:00 2001 From: Java Decompiler Date: Mon, 13 May 2019 21:54:31 +0200 Subject: [PATCH 001/211] Initial commit --- LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From e2e4ce473c3caf3fda9d0ac0d73dab8da86c7a1f Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 15 May 2019 08:05:41 +0200 Subject: [PATCH 002/211] Initial commit --- .gitattributes | 17 + .gitignore | 36 + LICENSE | 17 +- NOTICE | 1 + README.md | 112 + build.gradle | 33 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 52266 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 + gradlew.bat | 90 + settings.gradle | 9 + .../v1/ClassFileToJavaSourceDecompiler.java | 60 + .../java/org/jd/core/v1/api/Decompiler.java | 19 + .../org/jd/core/v1/api/loader/Loader.java | 14 + .../core/v1/api/loader/LoaderException.java | 18 + .../org/jd/core/v1/api/printer/Printer.java | 46 + .../jd/core/v1/model/classfile/ClassFile.java | 101 + .../core/v1/model/classfile/ConstantPool.java | 50 + .../jd/core/v1/model/classfile/Constants.java | 30 + .../org/jd/core/v1/model/classfile/Field.java | 48 + .../jd/core/v1/model/classfile/Method.java | 57 + .../model/classfile/attribute/Annotation.java | 26 + .../classfile/attribute/Annotations.java | 20 + .../model/classfile/attribute/Attribute.java | 10 + .../attribute/AttributeAnnotationDefault.java | 20 + .../attribute/AttributeBootstrapMethods.java | 20 + .../classfile/attribute/AttributeCode.java | 47 + .../attribute/AttributeConstantValue.java | 22 + .../attribute/AttributeDeprecated.java | 12 + .../attribute/AttributeExceptions.java | 20 + .../attribute/AttributeInnerClasses.java | 20 + .../attribute/AttributeLineNumberTable.java | 20 + .../AttributeLocalVariableTable.java | 20 + .../AttributeLocalVariableTypeTable.java | 20 + .../AttributeParameterAnnotations.java | 20 + .../attribute/AttributeSignature.java | 25 + .../attribute/AttributeSourceFile.java | 20 + .../attribute/AttributeSynthetic.java | 12 + .../classfile/attribute/BootstrapMethod.java | 26 + .../classfile/attribute/CodeException.java | 61 + .../classfile/attribute/ElementValue.java | 12 + .../ElementValueAnnotationValue.java | 25 + .../attribute/ElementValueArrayValue.java | 25 + .../attribute/ElementValueClassInfo.java | 25 + .../attribute/ElementValueEnumConstValue.java | 31 + .../classfile/attribute/ElementValuePair.java | 27 + .../attribute/ElementValuePrimitiveType.java | 37 + .../attribute/ElementValueVisitor.java | 16 + .../model/classfile/attribute/InnerClass.java | 38 + .../model/classfile/attribute/LineNumber.java | 31 + .../classfile/attribute/LocalVariable.java | 57 + .../attribute/LocalVariableType.java | 58 + .../classfile/attribute/UnknownAttribute.java | 12 + .../v1/model/classfile/constant/Constant.java | 37 + .../classfile/constant/ConstantClass.java | 21 + .../classfile/constant/ConstantDouble.java | 21 + .../classfile/constant/ConstantFloat.java | 21 + .../classfile/constant/ConstantInteger.java | 21 + .../classfile/constant/ConstantLong.java | 21 + .../classfile/constant/ConstantMemberRef.java | 30 + .../constant/ConstantMethodHandle.java | 27 + .../constant/ConstantMethodType.java | 21 + .../constant/ConstantNameAndType.java | 27 + .../classfile/constant/ConstantString.java | 21 + .../classfile/constant/ConstantUtf8.java | 21 + .../classfile/constant/ConstantValue.java | 14 + .../AbstractNopFlexibleFragmentVisitor.java | 16 + .../fragment/EndFlexibleBlockFragment.java | 19 + .../fragment/EndMovableBlockFragment.java | 24 + .../core/v1/model/fragment/FixedFragment.java | 36 + .../v1/model/fragment/FlexibleFragment.java | 86 + .../jd/core/v1/model/fragment/Fragment.java | 19 + .../v1/model/fragment/FragmentVisitor.java | 18 + .../SpacerBetweenMovableBlocksFragment.java | 24 + .../fragment/StartFlexibleBlockFragment.java | 20 + .../fragment/StartMovableBlockFragment.java | 31 + .../model/javafragment/EndBlockFragment.java | 68 + .../EndBlockInParameterFragment.java | 19 + .../model/javafragment/EndBodyFragment.java | 68 + .../EndBodyInParameterFragment.java | 39 + .../EndMovableJavaBlockFragment.java | 19 + .../EndSingleStatementBlockFragment.java | 68 + .../EndStatementsBlockFragment.java | 29 + .../model/javafragment/ImportsFragment.java | 111 + .../v1/model/javafragment/JavaFragment.java | 12 + .../javafragment/JavaFragmentVisitor.java | 33 + .../LineNumberTokensFragment.java | 90 + .../javafragment/SpaceSpacerFragment.java | 20 + .../SpacerBetweenMembersFragment.java | 22 + .../v1/model/javafragment/SpacerFragment.java | 21 + .../javafragment/StartBlockFragment.java | 71 + .../model/javafragment/StartBodyFragment.java | 71 + .../StartMovableJavaBlockFragment.java | 25 + .../StartSingleStatementBlockFragment.java | 71 + .../StartStatementsBlockFragment.java | 60 + .../StartStatementsDoWhileBlockFragment.java | 23 + ...artStatementsInfiniteForBlockFragment.java | 23 + ...tStatementsInfiniteWhileBlockFragment.java | 23 + .../StartStatementsTryBlockFragment.java | 23 + .../v1/model/javafragment/TokensFragment.java | 70 + .../javasyntax/AbstractJavaSyntaxVisitor.java | 624 ++++ .../v1/model/javasyntax/CompilationUnit.java | 22 + .../AbstractNopDeclarationVisitor.java | 33 + .../declaration/AnnotationDeclaration.java | 39 + .../declaration/ArrayVariableInitializer.java | 33 + .../declaration/BaseFieldDeclarator.java | 14 + .../declaration/BaseFormalParameter.java | 12 + .../BaseLocalVariableDeclarator.java | 14 + .../declaration/BaseMemberDeclaration.java | 13 + .../declaration/BaseTypeDeclaration.java | 11 + .../declaration/BodyDeclaration.java | 31 + .../declaration/ClassDeclaration.java | 40 + .../declaration/ConstructorDeclaration.java | 78 + .../javasyntax/declaration/Declaration.java | 26 + .../declaration/DeclarationVisitor.java | 33 + .../declaration/EnumDeclaration.java | 123 + .../ExpressionVariableInitializer.java | 53 + .../declaration/FieldDeclaration.java | 84 + .../declaration/FieldDeclarator.java | 88 + .../declaration/FieldDeclarators.java | 43 + .../declaration/FormalParameter.java | 91 + .../declaration/FormalParameters.java | 32 + .../InstanceInitializerDeclaration.java | 38 + .../declaration/InterfaceDeclaration.java | 52 + .../declaration/LocalVariableDeclaration.java | 46 + .../declaration/LocalVariableDeclarator.java | 88 + .../declaration/LocalVariableDeclarators.java | 36 + .../declaration/MemberDeclaration.java | 11 + .../declaration/MemberDeclarations.java | 36 + .../declaration/MethodDeclaration.java | 132 + .../StaticInitializerDeclaration.java | 38 + .../declaration/TypeDeclaration.java | 40 + .../declaration/TypeDeclarations.java | 24 + .../declaration/VariableInitializer.java | 12 + .../expression/AbstractLambdaExpression.java | 34 + .../AbstractLineNumberExpression.java | 30 + .../AbstractLineNumberTypeExpression.java | 32 + .../AbstractNopExpressionVisitor.java | 47 + .../expression/ArrayExpression.java | 63 + .../javasyntax/expression/BaseExpression.java | 14 + .../expression/BinaryOperatorExpression.java | 73 + .../expression/BooleanExpression.java | 50 + .../javasyntax/expression/CastExpression.java | 60 + .../expression/CommentExpression.java | 48 + .../ConstructorInvocationExpression.java | 48 + .../ConstructorReferenceExpression.java | 41 + .../expression/DoubleConstantExpression.java | 38 + .../EnumConstantReferenceExpression.java | 51 + .../javasyntax/expression/Expression.java | 66 + .../expression/ExpressionVisitor.java | 47 + .../javasyntax/expression/Expressions.java | 37 + .../expression/FieldReferenceExpression.java | 67 + .../expression/FloatConstantExpression.java | 38 + .../expression/InstanceOfExpression.java | 51 + .../expression/IntegerConstantExpression.java | 70 + .../LambdaFormalParametersExpression.java | 40 + .../LambdaIdentifiersExpression.java | 48 + .../expression/LengthExpression.java | 43 + .../LocalVariableReferenceExpression.java | 38 + .../expression/LongConstantExpression.java | 38 + .../MethodInvocationExpression.java | 55 + .../expression/MethodReferenceExpression.java | 54 + .../model/javasyntax/expression/NewArray.java | 38 + .../javasyntax/expression/NewExpression.java | 78 + .../expression/NewInitializedArray.java | 39 + .../expression/NewInnerExpression.java | 35 + .../javasyntax/expression/NullExpression.java | 30 + .../ObjectTypeReferenceExpression.java | 72 + .../expression/ParenthesesExpression.java | 33 + .../expression/PostOperatorExpression.java | 54 + .../expression/PreOperatorExpression.java | 54 + .../expression/StringConstantExpression.java | 43 + .../SuperConstructorInvocationExpression.java | 48 + .../expression/SuperExpression.java | 43 + .../expression/TernaryOperatorExpression.java | 91 + .../javasyntax/expression/ThisExpression.java | 54 + .../TypeReferenceDotClassExpression.java | 54 + .../AbstractNopReferenceVisitor.java | 18 + .../reference/AnnotationElementValue.java | 27 + .../reference/AnnotationReference.java | 76 + .../reference/AnnotationReferences.java | 30 + .../reference/BaseAnnotationReference.java | 10 + .../reference/BaseElementValue.java | 12 + .../reference/BaseElementValuePair.java | 12 + .../javasyntax/reference/ElementValue.java | 17 + ...mentValueArrayInitializerElementValue.java | 34 + .../reference/ElementValuePair.java | 36 + .../reference/ElementValuePairs.java | 35 + .../javasyntax/reference/ElementValues.java | 36 + .../reference/ExpressionElementValue.java | 32 + .../reference/InnerObjectReference.java | 40 + .../javasyntax/reference/ObjectReference.java | 34 + .../model/javasyntax/reference/Reference.java | 12 + .../reference/ReferenceVisitor.java | 21 + .../AbstractNopStatementVisitor.java | 40 + .../javasyntax/statement/AssertStatement.java | 37 + .../javasyntax/statement/BaseStatement.java | 14 + .../javasyntax/statement/BreakStatement.java | 33 + .../statement/ByteCodeStatement.java | 26 + .../statement/CommentStatement.java | 25 + .../statement/ContinueStatement.java | 33 + .../statement/DoWhileStatement.java | 37 + .../statement/ExpressionStatement.java | 36 + .../statement/ForEachStatement.java | 46 + .../javasyntax/statement/ForStatement.java | 76 + .../javasyntax/statement/IfElseStatement.java | 28 + .../javasyntax/statement/IfStatement.java | 37 + .../javasyntax/statement/LabelStatement.java | 36 + .../statement/LambdaExpressionStatement.java | 32 + .../LocalVariableDeclarationStatement.java | 29 + .../statement/ReturnExpressionStatement.java | 57 + .../javasyntax/statement/ReturnStatement.java | 24 + .../model/javasyntax/statement/Statement.java | 11 + .../statement/StatementVisitor.java | 40 + .../javasyntax/statement/Statements.java | 37 + .../javasyntax/statement/SwitchStatement.java | 143 + .../statement/SynchronizedStatement.java | 33 + .../javasyntax/statement/ThrowStatement.java | 32 + .../javasyntax/statement/TryStatement.java | 139 + .../statement/TypeDeclarationStatement.java | 27 + .../javasyntax/statement/WhileStatement.java | 37 + .../type/AbstractNopTypeVisitor.java | 25 + .../javasyntax/type/AbstractTypeVisitor.java | 90 + .../javasyntax/type/ArrayTypeArguments.java | 25 + .../v1/model/javasyntax/type/BaseType.java | 12 + .../javasyntax/type/BaseTypeArgument.java | 11 + .../javasyntax/type/BaseTypeParameter.java | 12 + .../javasyntax/type/DiamondTypeArgument.java | 19 + .../v1/model/javasyntax/type/GenericType.java | 76 + .../javasyntax/type/InnerObjectType.java | 89 + .../v1/model/javasyntax/type/ObjectType.java | 167 + .../model/javasyntax/type/PrimitiveType.java | 162 + .../core/v1/model/javasyntax/type/Type.java | 28 + .../model/javasyntax/type/TypeArgument.java | 12 + .../model/javasyntax/type/TypeBoundList.java | 11 + .../v1/model/javasyntax/type/TypeBounds.java | 28 + .../model/javasyntax/type/TypeParameter.java | 29 + .../type/TypeParameterWithTypeBounds.java | 31 + .../model/javasyntax/type/TypeParameters.java | 56 + .../model/javasyntax/type/TypeVisitable.java | 12 + .../v1/model/javasyntax/type/TypeVisitor.java | 25 + .../core/v1/model/javasyntax/type/Types.java | 36 + .../javasyntax/type/UnknownTypeArgument.java | 16 + .../type/WildcardExtendsTypeArgument.java | 30 + .../type/WildcardSuperTypeArgument.java | 30 + .../org/jd/core/v1/model/message/Message.java | 54 + .../jd/core/v1/model/processor/Processor.java | 14 + .../model/token/AbstractNopTokenVisitor.java | 25 + .../v1/model/token/BooleanConstantToken.java | 30 + .../model/token/CharacterConstantToken.java | 36 + .../core/v1/model/token/DeclarationToken.java | 55 + .../jd/core/v1/model/token/EndBlockToken.java | 37 + .../core/v1/model/token/EndMarkerToken.java | 38 + .../jd/core/v1/model/token/KeywordToken.java | 30 + .../core/v1/model/token/LineNumberToken.java | 37 + .../jd/core/v1/model/token/NewLineToken.java | 36 + .../v1/model/token/NumericConstantToken.java | 30 + .../core/v1/model/token/ReferenceToken.java | 39 + .../core/v1/model/token/StartBlockToken.java | 37 + .../core/v1/model/token/StartMarkerToken.java | 38 + .../v1/model/token/StringConstantToken.java | 36 + .../org/jd/core/v1/model/token/TextToken.java | 60 + .../org/jd/core/v1/model/token/Token.java | 12 + .../jd/core/v1/model/token/TokenVisitor.java | 25 + .../ClassFileToJavaSyntaxProcessor.java | 42 + .../model/cfg/BasicBlock.java | 513 ++++ .../model/cfg/ControlFlowGraph.java | 75 + .../classfiletojavasyntax/model/cfg/Loop.java | 79 + .../ClassFileAnnotationDeclaration.java | 30 + .../declaration/ClassFileBodyDeclaration.java | 142 + .../ClassFileClassDeclaration.java | 37 + .../ClassFileConstructorDeclaration.java | 93 + ...assFileConstructorOrMethodDeclaration.java | 36 + .../declaration/ClassFileEnumDeclaration.java | 60 + .../ClassFileFieldDeclaration.java | 77 + .../ClassFileInterfaceDeclaration.java | 32 + .../ClassFileMemberDeclaration.java | 14 + .../ClassFileMethodDeclaration.java | 107 + ...ClassFileStaticInitializerDeclaration.java | 83 + .../expression/ClassFileCmpExpression.java | 18 + ...sFileLocalVariableReferenceExpression.java | 45 + .../ClassFileBreakContinueStatement.java | 65 + .../statement/ClassFileForEachStatement.java | 31 + .../statement/ClassFileForStatement.java | 45 + .../ClassFileMonitorEnterStatement.java | 29 + .../ClassFileMonitorExitStatement.java | 29 + .../statement/ClassFileTryStatement.java | 68 + .../localvariable/AbstractLocalVariable.java | 128 + .../AbstractNopLocalVariableVisitor.java | 14 + .../model/localvariable/Frame.java | 838 +++++ .../localvariable/GenericLocalVariable.java | 55 + .../model/localvariable/LocalVariable.java | 22 + .../model/localvariable/LocalVariableSet.java | 178 ++ .../localvariable/LocalVariableVisitor.java | 14 + .../localvariable/ObjectLocalVariable.java | 280 ++ .../localvariable/PrimitiveLocalVariable.java | 172 ++ .../model/localvariable/RootFrame.java | 30 + .../processor/ConvertClassFileException.java | 18 + .../processor/ConvertClassFileProcessor.java | 274 ++ .../UpdateJavaSyntaxTreeProcessor.java | 34 + .../util/AggregateFieldsUtil.java | 76 + .../util/AnnotationConverter.java | 195 ++ .../util/ByteCodeParser.java | 2472 +++++++++++++++ .../util/ByteCodeWriter.java | 444 +++ .../util/ControlFlowGraphGotoReducer.java | 41 + .../util/ControlFlowGraphLoopReducer.java | 702 +++++ .../util/ControlFlowGraphMaker.java | 597 ++++ .../util/ControlFlowGraphReducer.java | 1407 +++++++++ .../util/CreateConcatStringUtil.java | 58 + .../util/ExceptionUtil.java | 15 + .../util/LocalVariableMaker.java | 573 ++++ .../util/LoopStatementMaker.java | 668 ++++ .../util/MergeMembersUtil.java | 146 + .../util/NewArrayMaker.java | 148 + .../util/ObjectTypeMaker.java | 457 +++ .../util/PrimitiveTypeUtil.java | 126 + .../util/ReflectionUtil.java | 135 + .../util/SignatureFormatException.java | 18 + .../util/SignatureParser.java | 782 +++++ .../util/StatementMaker.java | 973 ++++++ .../util/StringUtil.java | 67 + .../util/SwitchStatementMaker.java | 196 ++ .../util/SynchronizedStatementMaker.java | 101 + .../util/TryWithResourcesStatementMaker.java | 111 + .../classfiletojavasyntax/util/WatchDog.java | 54 + .../visitor/AggregateFieldsVisitor.java | 43 + .../visitor/CreateInstructionsVisitor.java | 135 + .../visitor/CreateLocalVariableVisitor.java | 76 + .../visitor/CreateParameterVisitor.java | 60 + ...DeclaredSyntheticLocalVariableVisitor.java | 129 + .../GenerateParameterSuffixNameVisitor.java | 51 + .../visitor/InitEnumVisitor.java | 121 + .../visitor/InitInnerClassVisitor.java | 623 ++++ .../visitor/InitInstanceFieldVisitor.java | 324 ++ .../visitor/InitStaticFieldVisitor.java | 181 ++ ...MergeTryWithResourcesStatementVisitor.java | 105 + .../PopulateBlackListNamesVisitor.java | 38 + ...RemoveBinaryOpReturnStatementsVisitor.java | 78 + .../RemoveDefaultConstructorVisitor.java | 140 + .../RemoveFinallyStatementsVisitor.java | 262 ++ .../visitor/SearchFirstLineNumberVisitor.java | 160 + .../SearchUndeclaredLocalVariableVisitor.java | 106 + .../visitor/SortMembersVisitor.java | 48 + .../UpdateIntegerConstantTypeVisitor.java | 490 +++ .../visitor/UpdateJavaSyntaxTreeVisitor.java | 90 + .../visitor/UpdateTypeVisitor.java | 43 + .../classfile/ClassFileDeserializer.java | 573 ++++ .../classfile/ClassFileFormatException.java | 18 + .../classfile/ClassFileReader.java | 105 + .../DeserializeClassFileProcessor.java | 31 + .../JavaSyntaxToJavaFragmentProcessor.java | 40 + .../util/CharacterUtil.java | 37 + .../util/JavaFragmentFactory.java | 210 ++ .../visitor/CompilationUnitVisitor.java | 1159 +++++++ .../visitor/ExpressionVisitor.java | 730 +++++ .../visitor/SearchImportsVisitor.java | 331 ++ .../visitor/SingleLineStatementVisitor.java | 300 ++ .../visitor/StatementVisitor.java | 677 +++++ .../visitor/TypeVisitor.java | 295 ++ .../layouter/LayoutFragmentProcessor.java | 127 + .../v1/service/layouter/model/Section.java | 457 +++ .../service/layouter/util/VisitorsHolder.java | 118 + ...ractSearchMovableBlockFragmentVisitor.java | 65 + ...ableBlockFragmentIndexVisitorAbstract.java | 44 + .../visitor/BuildSectionsVisitor.java | 36 + ...dateSpacerBetweenMovableBlocksVisitor.java | 70 + .../JavaFragmentToTokenProcessor.java | 37 + .../visitor/TokenizeJavaFragmentVisitor.java | 687 +++++ .../service/writer/WriteTokenProcessor.java | 45 + .../writer/visitor/PrintTokenVisitor.java | 208 ++ src/main/java/org/jd/core/v1/util/Base.java | 27 + .../java/org/jd/core/v1/util/DefaultList.java | 70 + .../org/jd/core/v1/util/DefaultStack.java | 96 + .../jd/core/v1/AggregateFieldsUtilTest.java | 148 + .../jd/core/v1/AnnotationConverterTest.java | 115 + .../jd/core/v1/ClassFileDeserializerTest.java | 107 + .../jd/core/v1/ClassFileToJavaSourceTest.java | 2030 +++++++++++++ .../core/v1/CodeExceptionComparatorTest.java | 38 + .../org/jd/core/v1/ControlFlowGraphTest.java | 2693 +++++++++++++++++ .../jd/core/v1/JavaFragmentToTokenTest.java | 1826 +++++++++++ .../core/v1/JavaSyntaxToJavaSourceTest.java | 665 ++++ .../core/v1/LayoutFragmentProcessorTest.java | 276 ++ .../org/jd/core/v1/MergeMembersUtilTest.java | 264 ++ .../org/jd/core/v1/ObjectTypeMakerTest.java | 200 ++ .../org/jd/core/v1/SignatureParserTest.java | 329 ++ src/test/java/org/jd/core/v1/TypeTest.java | 94 + ...SpacerBetweenMovableBlocksVisitorTest.java | 82 + .../java/org/jd/core/v1/WriteTokenTest.java | 300 ++ .../jd/core/v1/loader/ClassPathLoader.java | 45 + .../java/org/jd/core/v1/loader/NopLoader.java | 23 + .../java/org/jd/core/v1/loader/ZipLoader.java | 60 + .../core/v1/printer/PlainTextMetaPrinter.java | 102 + .../jd/core/v1/printer/PlainTextPrinter.java | 126 + .../type/visitor/PrintTypeVisitor.java | 156 + .../TestTokenizeJavaFragmentProcessor.java | 31 + .../TokenizeJavaFragmentTestVisitor.java | 172 ++ .../util/ControlFlowGraphPlantUMLWriter.java | 478 +++ .../org/jd/core/v1/util/PatternMaker.java | 45 + src/test/resources/apk/ContactManager.apk | Bin 0 -> 25931 bytes .../java/org/jd/core/test/AdvancedSwitch.java | 55 + .../java/org/jd/core/test/AnnotatedClass.java | 64 + .../java/org/jd/core/test/AnonymousClass.java | 117 + .../java/org/jd/core/test/Array.java | 104 + .../java/org/jd/core/test/Assert.java | 56 + .../java/org/jd/core/test/Basic.java | 185 ++ .../java/org/jd/core/test/BreakContinue.java | 178 ++ .../java/org/jd/core/test/Constructors.java | 45 + .../java/org/jd/core/test/DoWhile.java | 161 + .../resources/java/org/jd/core/test/Enum.java | 88 + .../resources/java/org/jd/core/test/For.java | 483 +++ .../java/org/jd/core/test/GenericClass.java | 110 + .../java/org/jd/core/test/IfElse.java | 204 ++ .../java/org/jd/core/test/InfiniteLayout.java | 25 + .../java/org/jd/core/test/Interface.java | 16 + .../test/InterfaceWithDefaultMethods.java | 35 + .../java/org/jd/core/test/Lambda.java | 72 + .../java/org/jd/core/test/Layout.java | 107 + .../java/org/jd/core/test/OuterClass.java | 188 ++ .../java/org/jd/core/test/Switch.java | 314 ++ .../java/org/jd/core/test/Synchronized.java | 158 + .../org/jd/core/test/TernaryOperator.java | 162 + .../org/jd/core/test/TryCatchFinally.java | 932 ++++++ .../jd/core/test/TryCatchMultiExceptions.java | 39 + .../org/jd/core/test/TryWithResources.java | 167 + .../java/org/jd/core/test/While.java | 437 +++ .../org/jd/core/test/annotation/Author.java | 13 + .../org/jd/core/test/annotation/Name.java | 14 + .../org/jd/core/test/annotation/Quality.java | 14 + .../org/jd/core/test/annotation/Value.java | 27 + ...data-java-eclipse-java-compiler-3.13.0.zip | Bin 0 -> 37354 bytes .../data-java-eclipse-java-compiler-3.2.1.zip | Bin 0 -> 27855 bytes .../data-java-eclipse-java-compiler-3.7.0.zip | Bin 0 -> 24256 bytes .../zip/data-java-harmony-jdk-r533500.zip | Bin 0 -> 19114 bytes .../resources/zip/data-java-ibm-j9_vm.zip | Bin 0 -> 44297 bytes .../resources/zip/data-java-jdk-1.1.8.zip | Bin 0 -> 23764 bytes .../resources/zip/data-java-jdk-1.3.1.zip | Bin 0 -> 21620 bytes .../resources/zip/data-java-jdk-1.4.2.zip | Bin 0 -> 22059 bytes .../resources/zip/data-java-jdk-1.5.0.zip | Bin 0 -> 39738 bytes .../resources/zip/data-java-jdk-1.6.0.zip | Bin 0 -> 55625 bytes .../zip/data-java-jdk-1.7.0-no-debug-info.zip | Bin 0 -> 4330 bytes .../resources/zip/data-java-jdk-1.7.0.zip | Bin 0 -> 63824 bytes .../resources/zip/data-java-jdk-1.8.0.zip | Bin 0 -> 67076 bytes .../resources/zip/data-java-jdk-10.0.2.zip | Bin 0 -> 14644 bytes .../resources/zip/data-java-jdk-9.0.1.zip | Bin 0 -> 14630 bytes .../zip/data-java-jikes-1.22-1.windows.zip | Bin 0 -> 19213 bytes .../zip/data-java-jrockit-90_150_06.zip | Bin 0 -> 37907 bytes 446 files changed, 50175 insertions(+), 8 deletions(-) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 NOTICE create mode 100644 README.md create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/org/jd/core/v1/ClassFileToJavaSourceDecompiler.java create mode 100644 src/main/java/org/jd/core/v1/api/Decompiler.java create mode 100644 src/main/java/org/jd/core/v1/api/loader/Loader.java create mode 100644 src/main/java/org/jd/core/v1/api/loader/LoaderException.java create mode 100644 src/main/java/org/jd/core/v1/api/printer/Printer.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/ClassFile.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/Constants.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/Field.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/Method.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/Annotations.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/Attribute.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeAnnotationDefault.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeBootstrapMethods.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeCode.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeConstantValue.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeDeprecated.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeExceptions.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeInnerClasses.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLineNumberTable.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTable.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTypeTable.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeParameterAnnotations.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSignature.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSourceFile.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSynthetic.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/BootstrapMethod.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValue.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueAnnotationValue.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueArrayValue.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueClassInfo.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePair.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePrimitiveType.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/InnerClass.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/LineNumber.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariable.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariableType.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/UnknownAttribute.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/Constant.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantClass.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantDouble.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantFloat.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantInteger.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantLong.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMemberRef.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodHandle.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodType.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantNameAndType.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantString.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantUtf8.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/constant/ConstantValue.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/AbstractNopFlexibleFragmentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/EndFlexibleBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/EndMovableBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/FixedFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/FlexibleFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/Fragment.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/FragmentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/SpacerBetweenMovableBlocksFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/StartFlexibleBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/fragment/StartMovableBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/EndBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/EndBlockInParameterFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/EndBodyFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/EndBodyInParameterFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/EndMovableJavaBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/EndSingleStatementBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/EndStatementsBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/JavaFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/JavaFragmentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/LineNumberTokensFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/SpaceSpacerFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/SpacerBetweenMembersFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/SpacerFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartBodyFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartMovableJavaBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartSingleStatementBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartStatementsBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartStatementsDoWhileBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteForBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteWhileBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/StartStatementsTryBlockFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javafragment/TokensFragment.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/CompilationUnit.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/ArrayVariableInitializer.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFieldDeclarator.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFormalParameter.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseLocalVariableDeclarator.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseTypeDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/BodyDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameter.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/InstanceInitializerDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarator.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/MethodDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/StaticInitializerDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLambdaExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberTypeExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/CommentExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/AbstractNopReferenceVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationElementValue.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReferences.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseAnnotationReference.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValue.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValuePair.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValue.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValueArrayInitializerElementValue.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePair.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/InnerObjectReference.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ObjectReference.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/Reference.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/reference/ReferenceVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ByteCodeStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/CommentStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/Statement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/SynchronizedStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/ThrowStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/TypeDeclarationStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/WhileStatement.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/BaseType.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeParameter.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgument.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBoundList.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBounds.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameter.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterWithTypeBounds.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameters.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitable.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/UnknownTypeArgument.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java create mode 100644 src/main/java/org/jd/core/v1/model/message/Message.java create mode 100644 src/main/java/org/jd/core/v1/model/processor/Processor.java create mode 100644 src/main/java/org/jd/core/v1/model/token/AbstractNopTokenVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/token/BooleanConstantToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/CharacterConstantToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/DeclarationToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/EndBlockToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/EndMarkerToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/KeywordToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/LineNumberToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/NewLineToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/NumericConstantToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/ReferenceToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/StartBlockToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/StartMarkerToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/StringConstantToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/TextToken.java create mode 100644 src/main/java/org/jd/core/v1/model/token/Token.java create mode 100644 src/main/java/org/jd/core/v1/model/token/TokenVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/BasicBlock.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/ControlFlowGraph.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/Loop.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMemberDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileCmpExpression.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileBreakContinueStatement.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileForEachStatement.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileForStatement.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileMonitorEnterStatement.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileMonitorExitStatement.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractNopLocalVariableVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileException.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AggregateFieldsUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphGotoReducer.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphLoopReducer.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ExceptionUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/NewArrayMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ReflectionUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureFormatException.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/WatchDog.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AggregateFieldsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/DeclaredSyntheticLocalVariableVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/MergeTryWithResourcesStatementVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFirstLineNumberVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchUndeclaredLocalVariableVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SortMembersVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateTypeVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java create mode 100644 src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileFormatException.java create mode 100644 src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileReader.java create mode 100644 src/main/java/org/jd/core/v1/service/deserializer/classfile/DeserializeClassFileProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/layouter/model/Section.java create mode 100644 src/main/java/org/jd/core/v1/service/layouter/util/VisitorsHolder.java create mode 100644 src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractSearchMovableBlockFragmentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractStoreMovableBlockFragmentIndexVisitorAbstract.java create mode 100644 src/main/java/org/jd/core/v1/service/layouter/visitor/BuildSectionsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/layouter/visitor/UpdateSpacerBetweenMovableBlocksVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/JavaFragmentToTokenProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/writer/WriteTokenProcessor.java create mode 100644 src/main/java/org/jd/core/v1/service/writer/visitor/PrintTokenVisitor.java create mode 100644 src/main/java/org/jd/core/v1/util/Base.java create mode 100644 src/main/java/org/jd/core/v1/util/DefaultList.java create mode 100644 src/main/java/org/jd/core/v1/util/DefaultStack.java create mode 100644 src/test/java/org/jd/core/v1/AggregateFieldsUtilTest.java create mode 100644 src/test/java/org/jd/core/v1/AnnotationConverterTest.java create mode 100644 src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java create mode 100644 src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java create mode 100644 src/test/java/org/jd/core/v1/CodeExceptionComparatorTest.java create mode 100644 src/test/java/org/jd/core/v1/ControlFlowGraphTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java create mode 100644 src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java create mode 100644 src/test/java/org/jd/core/v1/MergeMembersUtilTest.java create mode 100644 src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java create mode 100644 src/test/java/org/jd/core/v1/SignatureParserTest.java create mode 100644 src/test/java/org/jd/core/v1/TypeTest.java create mode 100644 src/test/java/org/jd/core/v1/UpdateSpacerBetweenMovableBlocksVisitorTest.java create mode 100644 src/test/java/org/jd/core/v1/WriteTokenTest.java create mode 100644 src/test/java/org/jd/core/v1/loader/ClassPathLoader.java create mode 100644 src/test/java/org/jd/core/v1/loader/NopLoader.java create mode 100644 src/test/java/org/jd/core/v1/loader/ZipLoader.java create mode 100644 src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java create mode 100644 src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java create mode 100644 src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java create mode 100644 src/test/java/org/jd/core/v1/services/tokenizer/javafragmenttotoken/TestTokenizeJavaFragmentProcessor.java create mode 100644 src/test/java/org/jd/core/v1/services/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentTestVisitor.java create mode 100644 src/test/java/org/jd/core/v1/util/ControlFlowGraphPlantUMLWriter.java create mode 100644 src/test/java/org/jd/core/v1/util/PatternMaker.java create mode 100644 src/test/resources/apk/ContactManager.apk create mode 100644 src/test/resources/java/org/jd/core/test/AdvancedSwitch.java create mode 100644 src/test/resources/java/org/jd/core/test/AnnotatedClass.java create mode 100644 src/test/resources/java/org/jd/core/test/AnonymousClass.java create mode 100644 src/test/resources/java/org/jd/core/test/Array.java create mode 100644 src/test/resources/java/org/jd/core/test/Assert.java create mode 100644 src/test/resources/java/org/jd/core/test/Basic.java create mode 100644 src/test/resources/java/org/jd/core/test/BreakContinue.java create mode 100644 src/test/resources/java/org/jd/core/test/Constructors.java create mode 100644 src/test/resources/java/org/jd/core/test/DoWhile.java create mode 100644 src/test/resources/java/org/jd/core/test/Enum.java create mode 100644 src/test/resources/java/org/jd/core/test/For.java create mode 100644 src/test/resources/java/org/jd/core/test/GenericClass.java create mode 100644 src/test/resources/java/org/jd/core/test/IfElse.java create mode 100644 src/test/resources/java/org/jd/core/test/InfiniteLayout.java create mode 100644 src/test/resources/java/org/jd/core/test/Interface.java create mode 100644 src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java create mode 100644 src/test/resources/java/org/jd/core/test/Lambda.java create mode 100644 src/test/resources/java/org/jd/core/test/Layout.java create mode 100644 src/test/resources/java/org/jd/core/test/OuterClass.java create mode 100644 src/test/resources/java/org/jd/core/test/Switch.java create mode 100644 src/test/resources/java/org/jd/core/test/Synchronized.java create mode 100644 src/test/resources/java/org/jd/core/test/TernaryOperator.java create mode 100644 src/test/resources/java/org/jd/core/test/TryCatchFinally.java create mode 100644 src/test/resources/java/org/jd/core/test/TryCatchMultiExceptions.java create mode 100644 src/test/resources/java/org/jd/core/test/TryWithResources.java create mode 100644 src/test/resources/java/org/jd/core/test/While.java create mode 100644 src/test/resources/java/org/jd/core/test/annotation/Author.java create mode 100644 src/test/resources/java/org/jd/core/test/annotation/Name.java create mode 100644 src/test/resources/java/org/jd/core/test/annotation/Quality.java create mode 100644 src/test/resources/java/org/jd/core/test/annotation/Value.java create mode 100644 src/test/resources/zip/data-java-eclipse-java-compiler-3.13.0.zip create mode 100644 src/test/resources/zip/data-java-eclipse-java-compiler-3.2.1.zip create mode 100644 src/test/resources/zip/data-java-eclipse-java-compiler-3.7.0.zip create mode 100644 src/test/resources/zip/data-java-harmony-jdk-r533500.zip create mode 100644 src/test/resources/zip/data-java-ibm-j9_vm.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.1.8.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.3.1.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.4.2.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.5.0.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.6.0.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.7.0.zip create mode 100644 src/test/resources/zip/data-java-jdk-1.8.0.zip create mode 100644 src/test/resources/zip/data-java-jdk-10.0.2.zip create mode 100644 src/test/resources/zip/data-java-jdk-9.0.1.zip create mode 100644 src/test/resources/zip/data-java-jikes-1.22-1.windows.zip create mode 100644 src/test/resources/zip/data-java-jrockit-90_150_06.zip diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d39b7ca1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Declare OSX files that will always have LF line endings on checkout. +Info.plist text eol=lf + +# Declare script files that will always have LF line endings on checkout. +*.sh text eol=lf + +# Declare script files that will always have CR/LF line endings on checkout. +*.bat text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.gif binary +*.icns binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8808e318 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Java +*.class + +# JD +debug* + +# Idea +.idea/ +out/ +*.ipr +*.iml +*.iws + +# Eclipse +.settings/ +classes/ +.classpath +.project + +# Mac +.DS_Store + +# Windows +Thumbs.db + +# Maven +log/ +target/ + +# Gradle +.gradle/ +build/ +!gradle/wrapper/* + +# WinMerge +*.bak diff --git a/LICENSE b/LICENSE index f288702d..eadd3930 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,8 @@ - GNU GENERAL PUBLIC LICENSE + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -631,8 +632,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + JD-Core, a JAVA decompiler + Copyright (C) 2008-2019 Emmanuel Dupuy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -645,14 +646,14 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) + JD-Core Copyright (C) 2008-2019 Emmanuel Dupuy This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -664,11 +665,11 @@ might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -. +. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. +. diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..fdffbb62 --- /dev/null +++ b/NOTICE @@ -0,0 +1 @@ +JD-Core license - GPLv3 diff --git a/README.md b/README.md new file mode 100644 index 00000000..0db611d7 --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ +# JD-Core + +JD-Core is a JAVA decompiler written in JAVA. + +- Java Decompiler projects home page: +[http://java-decompiler.github.io](http://java-decompiler.github.io) +- JD-GUI source code: +[https://github.com/java-decompiler/jd-core](https://github.com/java-decompiler/jd-core) +- Maven repository: +[https://raw.github.com/java-decompiler/mvn-repo/master](https://raw.github.com/java-decompiler/mvn-repo/master) + +## Description +JD-Core is a standalone JAVA library containing the JAVA decompiler of +"Java Decompiler project". It support Java 1.1.8 to Java 10.0, +including Lambda expressions, method references and default methods. +JD-Core is the engine of JD-GUI. + +## How to build JD-Core ? +``` +> git clone https://github.com/java-decompiler/jd-core.git +> cd jd-core +> ./gradlew build +``` +generate _"build/libs/jd-core-x.y.z.jar"_ + +## How to use JD-Core ? + +1. Implement the +_[jd.core.loader.Loader](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/loader/Loader.java)_ +interface, +2. Implement the +_[jd.core.printer.Printer](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/printer/Printer.java)_ +interface, +3. And call the method _"decompile(loader, printer, internalTypeName);"_ + +## Example + +1. Implement the _Loader_ interface: +```java +Loader loader = new Loader() { + @Override + public byte[] load(String internalName) throws LoaderException { + InputStream is = this.getClass().getResourceAsStream("/" + internalName + ".class"); + + if (is == null) { + return null; + } else { + try (InputStream in=is; ByteArrayOutputStream out=new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int read = in.read(buffer); + + while (read > 0) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + + return out.toByteArray(); + } catch (IOException e) { + throw new LoaderException(e); + } + } + } + + @Override + public boolean canLoad(String internalName) { + return this.getClass().getResource("/" + internalName + ".class") != null; + } +}; +``` + +2. Implement the _Printer_ interface +```java +Printer printer = new Printer() { + protected static final String TAB = " "; + protected static final String NEWLINE = "\n"; + + protected int indentationCount = 0; + protected StringBuilder sb = new StringBuilder(); + + @Override public String toString() { return sb.toString(); } + + @Override public void start(int maxLineNumber, int majorVersion, int minorVersion) {} + @Override public void end() {} + + @Override public void printText(String text) { sb.append(text); } + @Override public void printNumericConstant(String constant) { sb.append(constant); } + @Override public void printStringConstant(String constant, String ownerInternalName) { sb.append(constant); } + @Override public void printKeyword(String keyword) { sb.append(keyword); } + @Override public void printDeclaration(int flags, String internalTypeName, String name, String descriptor) { sb.append(name); } + @Override public void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName) { sb.append(name); } + + @Override public void indent() { this.indentationCount++; } + @Override public void unindent() { if (this.indentationCount > 0) this.indentationCount--; } + + @Override public void startLine(int lineNumber) { for (int i=0; i 0) sb.append(NEWLINE); } + + @Override public void startMarker(int type) {} + @Override public void endMarker(int type) {} +}; +``` + +3. And call the method _"decompile(loader, printer, internalTypeName);"_ +```java +ClassFileToJavaSourceDecompiler decompiler = new +ClassFileToJavaSourceDecompiler(); + +decompiler.decompile(loader, printer, "path/to/YourClass"); + +String source = printer.toString(); +``` diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..3038fffc --- /dev/null +++ b/build.gradle @@ -0,0 +1,33 @@ +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'idea' + +dependencies { + testCompile 'junit:junit:4.12' +} + +version='1.0.0' + +tasks.withType(JavaCompile) { + sourceCompatibility = targetCompatibility = '1.8' + options.compilerArgs << '-Xlint:deprecation' + options.compilerArgs << '-Xlint:unchecked' + options.encoding = 'UTF-8' +} + +repositories { + mavenCentral() +} + +jar { + manifest { + attributes 'JD-Core-Version': version + } +} + +// 'cleanIdea' task extension // +cleanIdea.doFirst { + delete project.name + '.iws' + delete 'out' + followSymlinks = true +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b5166dad4d90021f6a0b45268c0755719f1d5cd4 GIT binary patch literal 52266 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 z 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..9a6bf73b --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Mar 02 11:11:32 CET 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..91a7e269 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# 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 +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +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 + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + 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 +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "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 +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 + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # 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 + # 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\"" + fi + i=$((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" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@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 + +@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= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@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 + +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 init + +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 + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_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=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +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% + +: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 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..b698b033 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +rootProject.name='jd-core' + diff --git a/src/main/java/org/jd/core/v1/ClassFileToJavaSourceDecompiler.java b/src/main/java/org/jd/core/v1/ClassFileToJavaSourceDecompiler.java new file mode 100644 index 00000000..be378347 --- /dev/null +++ b/src/main/java/org/jd/core/v1/ClassFileToJavaSourceDecompiler.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import org.jd.core.v1.api.Decompiler; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; + +import java.util.Map; + +public class ClassFileToJavaSourceDecompiler implements Decompiler { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + public void decompile(Loader loader, Printer printer, String internalName) throws Exception { + Message message = new Message(); + + message.setHeader("mainInternalTypeName", internalName); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + decompile(message); + } + + public void decompile(Loader loader, Printer printer, String internalName, Map configuration) throws Exception { + Message message = new Message(); + + message.setHeader("mainInternalTypeName", internalName); + message.setHeader("configuration", configuration); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + decompile(message); + } + + protected void decompile(Message message) throws Exception { + this.deserializer.process(message); + this.converter.process(message); + this.fragmenter.process(message); + this.layouter.process(message); + this.tokenizer.process(message); + this.writer.process(message); + } +} diff --git a/src/main/java/org/jd/core/v1/api/Decompiler.java b/src/main/java/org/jd/core/v1/api/Decompiler.java new file mode 100644 index 00000000..260f5fe0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/api/Decompiler.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.api; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; + +import java.util.Map; + +public interface Decompiler { + void decompile(Loader loader, Printer printer, String internalName) throws Exception; + + void decompile(Loader loader, Printer printer, String internalName, Map configuration) throws Exception; +} diff --git a/src/main/java/org/jd/core/v1/api/loader/Loader.java b/src/main/java/org/jd/core/v1/api/loader/Loader.java new file mode 100644 index 00000000..d2b97dbe --- /dev/null +++ b/src/main/java/org/jd/core/v1/api/loader/Loader.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.api.loader; + +public interface Loader { + boolean canLoad(String internalName); + + byte[] load(String internalName) throws LoaderException; +} diff --git a/src/main/java/org/jd/core/v1/api/loader/LoaderException.java b/src/main/java/org/jd/core/v1/api/loader/LoaderException.java new file mode 100644 index 00000000..e5fda754 --- /dev/null +++ b/src/main/java/org/jd/core/v1/api/loader/LoaderException.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.api.loader; + + +public class LoaderException extends Exception { + private static final long serialVersionUID = 9506606333927794L; + public LoaderException() {} + + public LoaderException(String msg) { super(msg); } + + public LoaderException(Throwable cause) { super(cause); } +} diff --git a/src/main/java/org/jd/core/v1/api/printer/Printer.java b/src/main/java/org/jd/core/v1/api/printer/Printer.java new file mode 100644 index 00000000..bf2720fb --- /dev/null +++ b/src/main/java/org/jd/core/v1/api/printer/Printer.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.api.printer; + + +public interface Printer { + int UNKNOWN_LINE_NUMBER = 0; + + // Declaration & reference flags + int TYPE_FLAG = 1; + int FIELD_FLAG = 2; + int METHOD_FLAG = 4; + int CONSTRUCTOR_FLAG = 8; + + // Marker types + int COMMENT_TYPE = 1; + int JAVADOC_TYPE = 2; + int ERROR_TYPE = 3; + int IMPORT_STATEMENTS_TYPE = 4; + + void start(int maxLineNumber, int majorVersion, int minorVersion); + void end(); + + void printText(String text); + void printNumericConstant(String constant); + void printStringConstant(String constant, String ownerInternalName); + void printKeyword(String keyword); + + void printDeclaration(int flags, String internalTypeName, String name, String descriptor); + void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName); + + void indent(); + void unindent(); + + void startLine(int lineNumber); + void endLine(); + void extraLine(int count); + + void startMarker(int type); + void endMarker(int type); +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/ClassFile.java b/src/main/java/org/jd/core/v1/model/classfile/ClassFile.java new file mode 100644 index 00000000..6cc30ce0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/ClassFile.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile; + + +import org.jd.core.v1.model.classfile.attribute.Attribute; + +import java.util.List; +import java.util.Map; + +public class ClassFile { + protected int majorVersion; + protected int minorVersion; + protected int accessFlags; + protected String internalTypeName; + protected String superTypeName; + protected String[] interfaceTypeNames; + protected Field[] fields; + protected Method[] methods; + protected Map attributes; + + protected ClassFile outerClassFile; + protected List innerClassFiles; + + public ClassFile(int majorVersion, int minorVersion, int accessFlags, String internalTypeName, String superTypeName, String[] interfaceTypeNames, Field[] fields, Method[] methods, Map attributes) { + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.accessFlags = accessFlags; + this.internalTypeName = internalTypeName; + this.superTypeName = superTypeName; + this.interfaceTypeNames = interfaceTypeNames; + this.fields = fields; + this.methods = methods; + this.attributes = attributes; + } + + public int getMinorVersion() { + return minorVersion; + } + public int getMajorVersion() { + return majorVersion; + } + + public int getAccessFlags() { + return accessFlags; + } + public void setAccessFlags(int accessFlags) { + this.accessFlags = accessFlags; + } + + public String getInternalTypeName() { + return internalTypeName; + } + + public String getSuperTypeName() { + return superTypeName; + } + + public String[] getInterfaceTypeNames() { + return interfaceTypeNames; + } + + public Field[] getFields() { + return fields; + } + + public Method[] getMethods() { + return methods; + } + + @SuppressWarnings("unchecked") + public T getAttribute(String name) { + return (attributes == null) ? null : (T)attributes.get(name); + } + + public ClassFile getOuterClassFile() { + return outerClassFile; + } + + public void setOuterClassFile(ClassFile outerClassFile) { + this.outerClassFile = outerClassFile; + } + + public List getInnerClassFiles() { + return innerClassFiles; + } + + public void setInnerClassFiles(List innerClassFiles) { + this.innerClassFiles = innerClassFiles; + } + + @Override + public String toString() { + return "ClassFile{" + internalTypeName + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java b/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java new file mode 100644 index 00000000..330dbaf3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile; + + +import org.jd.core.v1.model.classfile.constant.*; + +public class ConstantPool { + protected Constant[] constants; + + public ConstantPool(Constant[] constants) { + this.constants = constants; + } + + @SuppressWarnings("unchecked") + public T getConstant(int index) { + return (T)constants[index]; + } + + public String getConstantTypeName(int classIndex) { + ConstantClass cc = (ConstantClass)constants[classIndex]; + ConstantUtf8 cutf8 = (ConstantUtf8)constants[cc.getNameIndex()]; + return cutf8.getValue(); + } + + public String getConstantString(int index) { + ConstantUtf8 cutf8 = (ConstantUtf8)constants[index]; + return cutf8.getValue(); + } + + public ConstantValue getConstantValue(int index) { + Constant constant = constants[index]; + + if ((constant != null) && (constant.getTag() == Constant.CONSTANT_String)) { + constant = constants[((ConstantString)constant).getStringIndex()]; + } + + return (ConstantValue)constant; + } + + @Override + public String toString() { + return "ConstantPool"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/Constants.java b/src/main/java/org/jd/core/v1/model/classfile/Constants.java new file mode 100644 index 00000000..31dc4daf --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/Constants.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile; + +public interface Constants { + // Access flag for Class, Field, Method, Nested class + short ACC_PUBLIC = 0x0001; // C F M N + short ACC_PRIVATE = 0x0002; // F M N + short ACC_PROTECTED = 0x0004; // F M N + short ACC_STATIC = 0x0008; // C F M N + short ACC_FINAL = 0x0010; // C F M N + short ACC_SYNCHRONIZED = 0x0020; // M + short ACC_SUPER = 0x0020; // C + short ACC_VOLATILE = 0x0040; // F + short ACC_BRIDGE = 0x0040; // M + short ACC_TRANSIENT = 0x0080; // F + short ACC_VARARGS = 0x0080; // M + short ACC_NATIVE = 0x0100; // M + short ACC_INTERFACE = 0x0200; // C N + short ACC_ABSTRACT = 0x0400; // C M N + short ACC_STRICT = 0x0800; // M + short ACC_SYNTHETIC = 0x1000; // C F M N + short ACC_ANNOTATION = 0x2000; // C N + short ACC_ENUM = 0x4000; // C F N +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/Field.java b/src/main/java/org/jd/core/v1/model/classfile/Field.java new file mode 100644 index 00000000..0508f41c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/Field.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile; + +import org.jd.core.v1.model.classfile.attribute.Attribute; + +import java.util.Map; + +public class Field { + protected int accessFlags; + protected String name; + protected String descriptor; + protected Map attributes; + + public Field(int accessFlags, String name, String descriptor, Map attributes) { + this.accessFlags = accessFlags; + this.name = name; + this.descriptor = descriptor; + this.attributes = attributes; + } + + public int getAccessFlags() { + return accessFlags; + } + + public String getName() { + return name; + } + + public String getDescriptor() { + return descriptor; + } + + @SuppressWarnings("unchecked") + public T getAttribute(String name) { + return (attributes == null) ? null : (T)attributes.get(name); + } + + @Override + public String toString() { + return "Field{" + name + " " + descriptor + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/Method.java b/src/main/java/org/jd/core/v1/model/classfile/Method.java new file mode 100644 index 00000000..1558a157 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/Method.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile; + +import org.jd.core.v1.model.classfile.attribute.Attribute; + +import java.util.Map; + +public class Method { + protected int accessFlags; + protected String name; + protected String descriptor; + protected Map attributes; + protected ConstantPool constants; + + public Method(int accessFlags, String name, String descriptor, Map attributes, ConstantPool constants) { + this.accessFlags = accessFlags; + this.name = name; + this.descriptor = descriptor; + this.attributes = attributes; + this.constants = constants; + } + + /** + * @see Constants + */ + public int getAccessFlags() { + return accessFlags; + } + + public String getName() { + return name; + } + + public String getDescriptor() { + return descriptor; + } + + @SuppressWarnings("unchecked") + public T getAttribute(String name) { + return (attributes == null) ? null : (T)attributes.get(name); + } + + public ConstantPool getConstants() { + return constants; + } + + @Override + public String toString() { + return "Method{" + name + " " + descriptor + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java new file mode 100644 index 00000000..31475e98 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class Annotation { + protected String typeName; + protected ElementValuePair[] elementValuePairs; + + public Annotation(String typeName, ElementValuePair[] elementValuePairs) { + this.typeName = typeName; + this.elementValuePairs = elementValuePairs; + } + + public String getTypeName() { + return typeName; + } + + public ElementValuePair[] getElementValuePairs() { + return elementValuePairs; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotations.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotations.java new file mode 100644 index 00000000..a028c467 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotations.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class Annotations implements Attribute { + protected Annotation[] annotations; + + public Annotations(Annotation[] annotations) { + this.annotations = annotations; + } + + public Annotation[] getAnnotations() { + return annotations; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/Attribute.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/Attribute.java new file mode 100644 index 00000000..e89e6a29 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/Attribute.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public interface Attribute {} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeAnnotationDefault.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeAnnotationDefault.java new file mode 100644 index 00000000..a597343d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeAnnotationDefault.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeAnnotationDefault implements Attribute { + protected ElementValue defaultValue; + + public AttributeAnnotationDefault(ElementValue defaultValue) { + this.defaultValue = defaultValue; + } + + public ElementValue getDefaultValue() { + return defaultValue; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeBootstrapMethods.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeBootstrapMethods.java new file mode 100644 index 00000000..5a7603f1 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeBootstrapMethods.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeBootstrapMethods implements Attribute { + protected BootstrapMethod[] bootstrapMethods; + + public AttributeBootstrapMethods(BootstrapMethod[] bootstrapMethods) { + this.bootstrapMethods = bootstrapMethods; + } + + public BootstrapMethod[] getBootstrapMethods() { + return bootstrapMethods; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeCode.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeCode.java new file mode 100644 index 00000000..1e4dee01 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeCode.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +import java.util.Map; + +public class AttributeCode implements Attribute { + protected int maxStack; + protected int maxLocals; + protected byte[] code; + protected CodeException[] exceptionTable; + protected Map attributes; + + public AttributeCode(int maxStack, int maxLocals, byte[] code, CodeException[] exceptionTable, Map attributes) { + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.code = code; + this.exceptionTable = exceptionTable; + this.attributes = attributes; + } + + public int getMaxStack() { + return maxStack; + } + + public int getMaxLocals() { + return maxLocals; + } + + public byte[] getCode() { + return code; + } + + public CodeException[] getExceptionTable() { + return exceptionTable; + } + + @SuppressWarnings("unchecked") + public T getAttribute(String name) { + return (attributes == null) ? null : (T)attributes.get(name); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeConstantValue.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeConstantValue.java new file mode 100644 index 00000000..6a4ef317 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeConstantValue.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +import org.jd.core.v1.model.classfile.constant.ConstantValue; + +public class AttributeConstantValue implements Attribute { + protected ConstantValue constantValue; + + public AttributeConstantValue(ConstantValue constantValue) { + this.constantValue = constantValue; + } + + public ConstantValue getConstantValue() { + return constantValue; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeDeprecated.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeDeprecated.java new file mode 100644 index 00000000..d3769ae7 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeDeprecated.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeDeprecated implements Attribute { + public AttributeDeprecated() {} +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeExceptions.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeExceptions.java new file mode 100644 index 00000000..9788f2ff --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeExceptions.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeExceptions implements Attribute { + protected String[] exceptionTypeNames; + + public AttributeExceptions(String[] exceptionTypeNames) { + this.exceptionTypeNames = exceptionTypeNames; + } + + public String[] getExceptionTypeNames() { + return exceptionTypeNames; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeInnerClasses.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeInnerClasses.java new file mode 100644 index 00000000..b5aa4b26 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeInnerClasses.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeInnerClasses implements Attribute { + protected InnerClass[] classes; + + public AttributeInnerClasses(InnerClass[] classes) { + this.classes = classes; + } + + public InnerClass[] getInnerClasses() { + return classes; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLineNumberTable.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLineNumberTable.java new file mode 100644 index 00000000..2ac5234b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLineNumberTable.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeLineNumberTable implements Attribute { + protected LineNumber[] lineNumberTable; + + public AttributeLineNumberTable(LineNumber[] lineNumberTable) { + this.lineNumberTable = lineNumberTable; + } + + public LineNumber[] getLineNumberTable() { + return lineNumberTable; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTable.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTable.java new file mode 100644 index 00000000..19fd9b1a --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTable.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeLocalVariableTable implements Attribute { + protected LocalVariable[] localVariableTable; + + public AttributeLocalVariableTable(LocalVariable[] localVariableTable) { + this.localVariableTable = localVariableTable; + } + + public LocalVariable[] getLocalVariableTable() { + return localVariableTable; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTypeTable.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTypeTable.java new file mode 100644 index 00000000..3954e4e6 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeLocalVariableTypeTable.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeLocalVariableTypeTable implements Attribute { + protected LocalVariableType[] localVariableTypeTable; + + public AttributeLocalVariableTypeTable(LocalVariableType[] localVariableTypeTable) { + this.localVariableTypeTable = localVariableTypeTable; + } + + public LocalVariableType[] getLocalVariableTypeTable() { + return localVariableTypeTable; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeParameterAnnotations.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeParameterAnnotations.java new file mode 100644 index 00000000..a20bcf6f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeParameterAnnotations.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeParameterAnnotations implements Attribute { + protected Annotations[] parameterAnnotations; + + public AttributeParameterAnnotations(Annotations[] parameterAnnotations) { + this.parameterAnnotations = parameterAnnotations; + } + + public Annotations[] getParameterAnnotations() { + return parameterAnnotations; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSignature.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSignature.java new file mode 100644 index 00000000..b0885343 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSignature.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeSignature implements Attribute { + protected String signature; + + public AttributeSignature(String signature) { + this.signature = signature; + } + + public String getSignature() { + return signature; + } + + @Override + public String toString() { + return "AttributeSignature{signature=" + signature + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSourceFile.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSourceFile.java new file mode 100644 index 00000000..5e0cc029 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSourceFile.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeSourceFile implements Attribute { + protected String sourceFile; + + public AttributeSourceFile(String sourceFile) { + this.sourceFile = sourceFile; + } + + public String getSourceFile() { + return sourceFile; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSynthetic.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSynthetic.java new file mode 100644 index 00000000..c60ecfe1 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeSynthetic.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeSynthetic implements Attribute { + public AttributeSynthetic() {} +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/BootstrapMethod.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/BootstrapMethod.java new file mode 100644 index 00000000..c6fa4426 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/BootstrapMethod.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class BootstrapMethod { + protected int bootstrapMethodRef; + protected int bootstrapArguments[]; + + public BootstrapMethod(int bootstrapMethodRef, int[] bootstrapArguments) { + this.bootstrapMethodRef = bootstrapMethodRef; + this.bootstrapArguments = bootstrapArguments; + } + + public int getBootstrapMethodRef() { + return bootstrapMethodRef; + } + + public int[] getBootstrapArguments() { + return bootstrapArguments; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java new file mode 100644 index 00000000..b7da57ad --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class CodeException { + protected int index; + protected int startPc; + protected int endPc; + protected int handlerPc; + protected int catchType; + + public CodeException(int index, int startPc, int endPc, int handlerPc, int catchType) { + this.index = index; + this.startPc = startPc; + this.endPc = endPc; + this.handlerPc = handlerPc; + this.catchType = catchType; + } + + public int getStartPc() { + return startPc; + } + + public int getEndPc() { + return endPc; + } + + public int getHandlerPc() { + return handlerPc; + } + + public int getCatchType() { + return catchType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CodeException that = (CodeException) o; + + if (startPc != that.startPc) return false; + return endPc == that.endPc; + } + + @Override + public int hashCode() { + return 31 * startPc + endPc; + } + + @Override + public String toString() { + return "CodeException{index=" + index + ", startPc=" + startPc + ", endPc=" + endPc + ", handlerPc=" + handlerPc + ", catchType=" + catchType + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValue.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValue.java new file mode 100644 index 00000000..395e0192 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValue.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public interface ElementValue { + void accept(ElementValueVisitor attribute); +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueAnnotationValue.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueAnnotationValue.java new file mode 100644 index 00000000..058ce85f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueAnnotationValue.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class ElementValueAnnotationValue implements ElementValue { + protected Annotation annotationValue; + + public ElementValueAnnotationValue(Annotation annotationValue) { + this.annotationValue = annotationValue; + } + + public Annotation getAnnotationValue() { + return annotationValue; + } + + @Override + public void accept(ElementValueVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueArrayValue.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueArrayValue.java new file mode 100644 index 00000000..d820b860 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueArrayValue.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class ElementValueArrayValue implements ElementValue { + protected ElementValue[] values; + + public ElementValueArrayValue(ElementValue[] values) { + this.values = values; + } + + public ElementValue[] getValues() { + return values; + } + + @Override + public void accept(ElementValueVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueClassInfo.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueClassInfo.java new file mode 100644 index 00000000..55d1aaed --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueClassInfo.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class ElementValueClassInfo implements ElementValue { + protected String classInfo; + + public ElementValueClassInfo(String classInfo) { + this.classInfo = classInfo; + } + + public String getClassInfo() { + return classInfo; + } + + @Override + public void accept(ElementValueVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java new file mode 100644 index 00000000..77c2a02d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class ElementValueEnumConstValue implements ElementValue { + protected String typeName; + protected String constName; + + public ElementValueEnumConstValue(String typeName, String constName) { + this.typeName = typeName; + this.constName = constName; + } + + public String getTypeName() { + return typeName; + } + + public String getConstName() { + return constName; + } + + @Override + public void accept(ElementValueVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePair.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePair.java new file mode 100644 index 00000000..9fc91c79 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePair.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class ElementValuePair { + protected String elementName; + protected ElementValue elementValue; + + public ElementValuePair(String elementName, ElementValue elementValue) { + this.elementName = elementName; + this.elementValue = elementValue; + } + + public String getElementName() { + return elementName; + } + + @SuppressWarnings("unchecked") + public T getElementValue() { + return (T)elementValue; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePrimitiveType.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePrimitiveType.java new file mode 100644 index 00000000..9c12bb51 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValuePrimitiveType.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +import org.jd.core.v1.model.classfile.constant.ConstantValue; + +public class ElementValuePrimitiveType implements ElementValue { + /* + * type = {'B', 'D', 'F', 'I', 'J', 'S', 'Z', 'C', 's'} + */ + protected int type; + protected ConstantValue constValue; + + public ElementValuePrimitiveType(int type, ConstantValue constValue) { + this.type = type; + this.constValue = constValue; + } + + public int getType() { + return type; + } + + @SuppressWarnings("unchecked") + public T getConstValue() { + return (T)constValue; + } + + @Override + public void accept(ElementValueVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueVisitor.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueVisitor.java new file mode 100644 index 00000000..68653e6f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueVisitor.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public interface ElementValueVisitor { + void visit(ElementValuePrimitiveType elementValue); + void visit(ElementValueClassInfo elementValue); + void visit(ElementValueAnnotationValue elementValue); + void visit(ElementValueEnumConstValue elementValue); + void visit(ElementValueArrayValue elementValue); +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/InnerClass.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/InnerClass.java new file mode 100644 index 00000000..a20c4f4b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/InnerClass.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class InnerClass { + protected String innerTypeName; + protected String outerTypeName; + protected String innerName; + protected int innerAccessFlags; + + public InnerClass(String innerTypeName, String outerTypeName, String innerName, int innerAccessFlags) { + this.innerTypeName = innerTypeName; + this.outerTypeName = outerTypeName; + this.innerName = innerName; + this.innerAccessFlags = innerAccessFlags; + } + + public String getInnerTypeName() { + return innerTypeName; + } + + public String getOuterTypeName() { + return outerTypeName; + } + + public String getInnerName() { + return innerName; + } + + public int getInnerAccessFlags() { + return innerAccessFlags; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/LineNumber.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/LineNumber.java new file mode 100644 index 00000000..48142027 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/LineNumber.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class LineNumber { + protected int startPc; + protected int lineNumber; + + public LineNumber(int startPc, int lineNumber) { + this.startPc = startPc; + this.lineNumber = lineNumber; + } + + public int getStartPc() { + return startPc; + } + + public int getLineNumber() { + return lineNumber; + } + + @Override + public String toString() { + return "LineNumber{startPc=" + startPc + ", lineNumber=" + lineNumber + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariable.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariable.java new file mode 100644 index 00000000..66d8035a --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariable.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class LocalVariable { + protected int startPc; + protected int length; + protected String name; + protected String descriptor; + protected int index; + + public LocalVariable(int startPc, int length, String name, String descriptor, int index) { + this.startPc = startPc; + this.length = length; + this.name = name; + this.descriptor = descriptor; + this.index = index; + } + + public int getStartPc() { + return startPc; + } + + public int getLength() { + return length; + } + + public String getName() { + return name; + } + + public String getDescriptor() { + return descriptor; + } + + public int getIndex() { + return index; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("LocalVariable{index=").append(index); + sb.append(", name=").append(name); + sb.append(", descriptor=").append(descriptor); + sb.append(", startPc=").append(startPc); + sb.append(", length=").append(length); + + return sb.append("}").toString(); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariableType.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariableType.java new file mode 100644 index 00000000..830b9383 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/LocalVariableType.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class LocalVariableType { + protected int startPc; + protected int length; + protected String name; + protected String signature; + protected int index; + + public LocalVariableType(int startPc, int length, String name, String signature, int index) { + this.startPc = startPc; + this.length = length; + this.name = name; + this.signature = signature; + this.index = index; + } + + public int getStartPc() { + return startPc; + } + + public int getLength() { + return length; + } + + public String getName() { + return name; + } + + public String getSignature() { + return signature; + } + + public int getIndex() { + return index; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("LocalVariableType{index=").append(index); + sb.append(", name=").append(name); + sb.append(", signature=").append(signature); + sb.append(", index=").append(index); + sb.append(", startPc=").append(startPc); + sb.append(", length=").append(length); + + return sb.append("}").toString(); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/UnknownAttribute.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/UnknownAttribute.java new file mode 100644 index 00000000..5bcec732 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/UnknownAttribute.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class UnknownAttribute implements Attribute { + public UnknownAttribute() {} +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/Constant.java b/src/main/java/org/jd/core/v1/model/classfile/constant/Constant.java new file mode 100644 index 00000000..69286306 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/Constant.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public abstract class Constant { + public static final byte CONSTANT_Unknown = 0; + public static final byte CONSTANT_Utf8 = 1; + public static final byte CONSTANT_Integer = 3; + public static final byte CONSTANT_Float = 4; + public static final byte CONSTANT_Long = 5; + public static final byte CONSTANT_Double = 6; + public static final byte CONSTANT_Class = 7; + public static final byte CONSTANT_String = 8; + public static final byte CONSTANT_FieldRef = 9; + public static final byte CONSTANT_MethodRef = 10; + public static final byte CONSTANT_InterfaceMethodRef = 11; + public static final byte CONSTANT_NameAndType = 12; + public static final byte CONSTANT_MethodHandle = 15; + public static final byte CONSTANT_MethodType = 16; + public static final byte CONSTANT_InvokeDynamic = 18; + public static final byte CONSTANT_MemberRef = 19; // Unofficial constant + + protected byte tag; + + public Constant(byte tag) { + this.tag = tag; + } + + public byte getTag() { + return tag; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantClass.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantClass.java new file mode 100644 index 00000000..bcad1db6 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantClass.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantClass extends Constant { + protected int nameIndex; + + public ConstantClass(int nameIndex) { + super(CONSTANT_Class); + this.nameIndex = nameIndex; + } + + public int getNameIndex() { + return nameIndex; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantDouble.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantDouble.java new file mode 100644 index 00000000..adf3ccea --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantDouble.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantDouble extends ConstantValue { + protected double value; + + public ConstantDouble(double value) { + super(CONSTANT_Double); + this.value = value; + } + + public double getValue() { + return value; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantFloat.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantFloat.java new file mode 100644 index 00000000..f885e9c7 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantFloat.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantFloat extends ConstantValue { + protected float value; + + public ConstantFloat(float value) { + super(CONSTANT_Float); + this.value = value; + } + + public float getValue() { + return value; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantInteger.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantInteger.java new file mode 100644 index 00000000..db850d9e --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantInteger.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantInteger extends ConstantValue { + protected int value; + + public ConstantInteger(int value) { + super(CONSTANT_Integer); + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantLong.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantLong.java new file mode 100644 index 00000000..3edba972 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantLong.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantLong extends ConstantValue { + protected long value; + + public ConstantLong(long value) { + super(CONSTANT_Long); + this.value = value; + } + + public long getValue() { + return value; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMemberRef.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMemberRef.java new file mode 100644 index 00000000..596bf090 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMemberRef.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +/** + * POJO for CONSTANT_Fieldref, CONSTANT_Methodref and CONSTANT_InterfaceMethodref. + */ +public class ConstantMemberRef extends Constant { + protected int classIndex; + protected int nameAndTypeIndex; + + public ConstantMemberRef(int classIndex, int nameAndTypeIndex) { + super(CONSTANT_MemberRef); + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public int getClassIndex() { + return classIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodHandle.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodHandle.java new file mode 100644 index 00000000..7ac49d64 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodHandle.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantMethodHandle extends Constant { + protected int referenceKind; + protected int referenceIndex; + + public ConstantMethodHandle(int referenceKind, int referenceIndex) { + super(CONSTANT_MethodHandle); + this.referenceKind = referenceKind; + this.referenceIndex = referenceIndex; + } + + public int getReferenceKind() { + return referenceKind; + } + + public int getReferenceIndex() { + return referenceIndex; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodType.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodType.java new file mode 100644 index 00000000..fa1420ed --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantMethodType.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantMethodType extends Constant { + protected int descriptorIndex; + + public ConstantMethodType(int descriptorIndex) { + super(CONSTANT_MethodType); + this.descriptorIndex = descriptorIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantNameAndType.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantNameAndType.java new file mode 100644 index 00000000..e928bc78 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantNameAndType.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantNameAndType extends Constant { + protected int nameIndex; + protected int descriptorIndex; + + public ConstantNameAndType(int nameIndex, int descriptorIndex) { + super(CONSTANT_NameAndType); + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantString.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantString.java new file mode 100644 index 00000000..a585560f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantString.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantString extends Constant { + protected int stringIndex; + + public ConstantString(int stringIndex) { + super(CONSTANT_String); + this.stringIndex = stringIndex; + } + + public int getStringIndex() { + return stringIndex; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantUtf8.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantUtf8.java new file mode 100644 index 00000000..dc497b3b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantUtf8.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public class ConstantUtf8 extends ConstantValue { + protected String value; + + public ConstantUtf8(String value) { + super(CONSTANT_Utf8); + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantValue.java b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantValue.java new file mode 100644 index 00000000..4344b935 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/constant/ConstantValue.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.constant; + +public abstract class ConstantValue extends Constant { + protected ConstantValue(byte tag) { + super(tag); + } +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/AbstractNopFlexibleFragmentVisitor.java b/src/main/java/org/jd/core/v1/model/fragment/AbstractNopFlexibleFragmentVisitor.java new file mode 100644 index 00000000..c703e8f3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/AbstractNopFlexibleFragmentVisitor.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public abstract class AbstractNopFlexibleFragmentVisitor implements FragmentVisitor { + @Override public void visit(EndFlexibleBlockFragment fragment) {} + @Override public void visit(EndMovableBlockFragment fragment) {} + @Override public void visit(StartFlexibleBlockFragment fragment) {} + @Override public void visit(StartMovableBlockFragment fragment) {} + @Override public void visit(FixedFragment fragment) {} +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/EndFlexibleBlockFragment.java b/src/main/java/org/jd/core/v1/model/fragment/EndFlexibleBlockFragment.java new file mode 100644 index 00000000..10f0ea06 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/EndFlexibleBlockFragment.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public abstract class EndFlexibleBlockFragment extends StartFlexibleBlockFragment { + protected EndFlexibleBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + @Override + public void accept(FragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/EndMovableBlockFragment.java b/src/main/java/org/jd/core/v1/model/fragment/EndMovableBlockFragment.java new file mode 100644 index 00000000..b881e8ee --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/EndMovableBlockFragment.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public class EndMovableBlockFragment extends FlexibleFragment { + public EndMovableBlockFragment() { + super(0, 0, 0, 0, "End movable block"); + } + + @Override + public String toString() { + return "{end-movable-block}"; + } + + @Override + public void accept(FragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/FixedFragment.java b/src/main/java/org/jd/core/v1/model/fragment/FixedFragment.java new file mode 100644 index 00000000..16889ad0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/FixedFragment.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public abstract class FixedFragment implements Fragment { + protected final int firstLineNumber; + protected final int lastLineNumber; + + public FixedFragment(int firstLineNumber, int lastLineNumber) { + this.firstLineNumber = firstLineNumber; + this.lastLineNumber = lastLineNumber; + } + + public int getFirstLineNumber() { + return firstLineNumber; + } + + public int getLastLineNumber() { + return lastLineNumber; + } + + @Override + public String toString() { + return "{first-line-number=" + firstLineNumber + ", last-line-number=" + lastLineNumber + "}"; + } + + @Override + public void accept(FragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/FlexibleFragment.java b/src/main/java/org/jd/core/v1/model/fragment/FlexibleFragment.java new file mode 100644 index 00000000..77744a15 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/FlexibleFragment.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public abstract class FlexibleFragment implements Fragment { + protected final int minimalLineCount; + protected int maximalLineCount; + protected int initialLineCount; + protected int lineCount; + protected final int weight; + protected final String label; + + public FlexibleFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + this.minimalLineCount = minimalLineCount; + this.maximalLineCount = maximalLineCount; + this.initialLineCount = this.lineCount = lineCount; + this.weight = weight; + this.label = label; + } + + public void resetLineCount() { + lineCount = initialLineCount; + } + + public int getMinimalLineCount() { + return minimalLineCount; + } + + public int getMaximalLineCount() { + return maximalLineCount; + } + + public int getInitialLineCount() { + return initialLineCount; + } + + public int getLineCount() { + return lineCount; + } + + public int getWeight() { + return weight; + } + + public String getLabel() { + return label; + } + + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + return true; + } else { + return false; + } + } + + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return "{minimal-line-count=" + getMinimalLineCount() + + ", maximal-line-count=" + getMaximalLineCount() + + ", initial-line-count=" + getInitialLineCount() + + ", line-count=" + getLineCount() + + ", weight=" + getWeight() + + (getLabel() != null ? ", label='" + label + "'}": "}"); + } + + @Override + public void accept(FragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/Fragment.java b/src/main/java/org/jd/core/v1/model/fragment/Fragment.java new file mode 100644 index 00000000..a187300c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/Fragment.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +/** + * A fragment_OLD is a part of a concrete syntax tree. A fragment_OLD can be compacted, expanded and/or moved to match the + * original line numbers. + * + * @see FixedFragment + * @see FlexibleFragment + */ +public interface Fragment { + void accept(FragmentVisitor visitor); +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/FragmentVisitor.java b/src/main/java/org/jd/core/v1/model/fragment/FragmentVisitor.java new file mode 100644 index 00000000..c0b97778 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/FragmentVisitor.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public interface FragmentVisitor { + void visit(FlexibleFragment fragment); + void visit(EndFlexibleBlockFragment fragment); + void visit(EndMovableBlockFragment fragment); + void visit(SpacerBetweenMovableBlocksFragment fragment); + void visit(StartFlexibleBlockFragment fragment); + void visit(StartMovableBlockFragment fragment); + void visit(FixedFragment fragment); +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/SpacerBetweenMovableBlocksFragment.java b/src/main/java/org/jd/core/v1/model/fragment/SpacerBetweenMovableBlocksFragment.java new file mode 100644 index 00000000..e375f59a --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/SpacerBetweenMovableBlocksFragment.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + + +public class SpacerBetweenMovableBlocksFragment extends FlexibleFragment { + public SpacerBetweenMovableBlocksFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public void setInitialLineCount(int initialLineCount) { + this.initialLineCount = this.lineCount = initialLineCount; + } + + @Override + public void accept(FragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/StartFlexibleBlockFragment.java b/src/main/java/org/jd/core/v1/model/fragment/StartFlexibleBlockFragment.java new file mode 100644 index 00000000..d6cccdef --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/StartFlexibleBlockFragment.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public abstract class StartFlexibleBlockFragment extends FlexibleFragment { + + protected StartFlexibleBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + @Override + public void accept(FragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/fragment/StartMovableBlockFragment.java b/src/main/java/org/jd/core/v1/model/fragment/StartMovableBlockFragment.java new file mode 100644 index 00000000..10c8dbc9 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/fragment/StartMovableBlockFragment.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.fragment; + +public class StartMovableBlockFragment extends FlexibleFragment { + protected int type; + + public StartMovableBlockFragment(int type) { + super(0, 0, 0, 0, "Start movable block"); + this.type = type; + } + + public int getType() { + return type; + } + + @Override + public String toString() { + return "{start-movable-block}"; + } + + @Override + public void accept(FragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/EndBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/EndBlockFragment.java new file mode 100644 index 00000000..1071773e --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/EndBlockFragment.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.EndFlexibleBlockFragment; + +public class EndBlockFragment extends EndFlexibleBlockFragment implements JavaFragment { + protected StartBlockFragment start; + + public EndBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, StartBlockFragment start) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + this.start = start; + start.setEndArrayInitializerBlockFragment(this); + } + + public void setLineCount(int lineCount) { + this.lineCount = lineCount; + } + + public StartBlockFragment getStartArrayInitializerBlockFragment() { + return start; + } + + @Override + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + +// if (!force) { +// // Update start body fragment +// if ((lineCount == 1) && (start.getLineCount() == 0)) { +// start.setLineCount(lineCount); +// } +// } + + return true; + } else { + return false; + } + } + + @Override + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + +// if (!force) { +// if (lineCount == 0) { +// start.setLineCount(lineCount); +// } +// } + + return true; + } else { + return false; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/EndBlockInParameterFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/EndBlockInParameterFragment.java new file mode 100644 index 00000000..cdd4b4dc --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/EndBlockInParameterFragment.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public class EndBlockInParameterFragment extends EndBlockFragment implements JavaFragment { + public EndBlockInParameterFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, StartBlockFragment start) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label, start); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/EndBodyFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/EndBodyFragment.java new file mode 100644 index 00000000..240c962b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/EndBodyFragment.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.EndFlexibleBlockFragment; + +public class EndBodyFragment extends EndFlexibleBlockFragment implements JavaFragment { + protected final StartBodyFragment start; + + public EndBodyFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, StartBodyFragment start) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + this.start = start; + start.setEndBodyFragment(this); + } + + public void setLineCount(int lineCount) { + this.lineCount = lineCount; + } + + public StartBodyFragment getStartBodyFragment() { + return start; + } + + @Override + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + + if (!force) { + // Update start body fragment + if ((lineCount == 1) && (start.getLineCount() == 0)) { + start.setLineCount(lineCount); + } + } + + return true; + } else { + return false; + } + } + + @Override + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + + if (!force) { + if (lineCount == 0) { + start.setLineCount(lineCount); + } + } + + return true; + } else { + return false; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/EndBodyInParameterFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/EndBodyInParameterFragment.java new file mode 100644 index 00000000..052acfeb --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/EndBodyInParameterFragment.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public class EndBodyInParameterFragment extends EndBodyFragment implements JavaFragment { + public EndBodyInParameterFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, StartBodyFragment startBodyFragment) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label, startBodyFragment); + } + + @Override + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + return true; + } else { + return false; + } + } + + @Override + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + return true; + } else { + return false; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/EndMovableJavaBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/EndMovableJavaBlockFragment.java new file mode 100644 index 00000000..e775e36e --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/EndMovableJavaBlockFragment.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.EndMovableBlockFragment; + +public class EndMovableJavaBlockFragment extends EndMovableBlockFragment implements JavaFragment { + public static final EndMovableJavaBlockFragment END_MOVABLE_BLOCK = new EndMovableJavaBlockFragment(); + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/EndSingleStatementBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/EndSingleStatementBlockFragment.java new file mode 100644 index 00000000..ac58baf4 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/EndSingleStatementBlockFragment.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.EndFlexibleBlockFragment; + +public class EndSingleStatementBlockFragment extends EndFlexibleBlockFragment implements JavaFragment { + protected final StartSingleStatementBlockFragment start; + + public EndSingleStatementBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, StartSingleStatementBlockFragment start) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + this.start = start; + start.setEndSingleStatementBlockFragment(this); + } + + public void setLineCount(int lineCount) { + this.lineCount = lineCount; + } + + public StartSingleStatementBlockFragment getStartSingleStatementBlockFragment() { + return start; + } + + @Override + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + + if (!force) { + // Update start body fragment + if (start.getLineCount() == 0) { + start.setLineCount(1); + } + } + + return true; + } else { + return false; + } + } + + @Override + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + + if (!force) { + if (lineCount == 0) { + start.setLineCount(0); + } + } + + return true; + } else { + return false; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/EndStatementsBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/EndStatementsBlockFragment.java new file mode 100644 index 00000000..0b0688f5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/EndStatementsBlockFragment.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.EndFlexibleBlockFragment; + +public class EndStatementsBlockFragment extends EndFlexibleBlockFragment implements JavaFragment { + protected final StartStatementsBlockFragment.Group group; + + public EndStatementsBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, StartStatementsBlockFragment.Group group) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + this.group = group; + group.add(this); + } + + public StartStatementsBlockFragment.Group getGroup() { + return group; + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java new file mode 100644 index 00000000..44ca2601 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.FlexibleFragment; +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; + + +public class ImportsFragment extends FlexibleFragment implements JavaFragment { + protected static final ImportCountComparator COUNT_COMPARATOR = new ImportCountComparator(); + + protected final HashMap importMap = new HashMap<>(); + + public ImportsFragment(int weight) { + super(0, -1, -1, weight, "Imports"); + } + + public void addImport(String internalName, String qualifiedName) { + Import imp = importMap.get(internalName); + + if (imp == null) { + importMap.put(internalName, new Import(internalName, qualifiedName)); + } else { + imp.incCounter(); + } + } + + public boolean isEmpty() { + return importMap.isEmpty(); + } + + public void initLineCounts() { + maximalLineCount = initialLineCount = lineCount = importMap.size(); + } + + public boolean contains(String internalName) { + return importMap.containsKey(internalName); + } + + @Override + public int getLineCount() { + assert (lineCount != -1) : "Call initLineCounts() before"; + return lineCount; + } + + public Collection getImports() { + int lineCount = getLineCount(); + int size = importMap.size(); + + if (lineCount < size) { + DefaultList imports = new DefaultList<>(importMap.values()); + + imports.sort(COUNT_COMPARATOR); + + // Remove less used imports + imports.subList(lineCount, size).clear(); + + return imports; + } else { + return importMap.values(); + } + } + + public static class Import { + protected String internalName; + protected String qualifiedName; + protected int counter; + + public Import(String internalName, String qualifiedName) { + this.internalName = internalName; + this.qualifiedName = qualifiedName; + this.counter = 1; + } + + public String getInternalName() { + return internalName; + } + public String getQualifiedName() { + return qualifiedName; + } + public int getCounter() { + return counter; + } + public void incCounter() { + counter++; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } + + protected static class ImportCountComparator implements Comparator { + public int compare(Import tr1, Import tr2) { + return tr2.getCounter() - tr1.getCounter(); + } + public boolean equals(Object obj) { + return this.equals(obj); + } + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/JavaFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/JavaFragment.java new file mode 100644 index 00000000..25be9c98 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/JavaFragment.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public interface JavaFragment { + void accept(JavaFragmentVisitor visitor); +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/JavaFragmentVisitor.java b/src/main/java/org/jd/core/v1/model/javafragment/JavaFragmentVisitor.java new file mode 100644 index 00000000..63d87e7b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/JavaFragmentVisitor.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public interface JavaFragmentVisitor { + void visit(EndBodyFragment fragment); + void visit(EndBlockInParameterFragment fragment); + void visit(EndBlockFragment fragment); + void visit(EndBodyInParameterFragment fragment); + void visit(EndMovableJavaBlockFragment fragment); + void visit(EndSingleStatementBlockFragment fragment); + void visit(EndStatementsBlockFragment fragment); + void visit(ImportsFragment fragment); + void visit(LineNumberTokensFragment fragment); + void visit(SpacerBetweenMembersFragment fragment); + void visit(SpacerFragment fragment); + void visit(SpaceSpacerFragment fragment); + void visit(StartBlockFragment fragment); + void visit(StartBodyFragment fragment); + void visit(StartMovableJavaBlockFragment fragment); + void visit(StartSingleStatementBlockFragment fragment); + void visit(StartStatementsBlockFragment fragment); + void visit(StartStatementsDoWhileBlockFragment fragment); + void visit(StartStatementsInfiniteForBlockFragment fragment); + void visit(StartStatementsInfiniteWhileBlockFragment fragment); + void visit(StartStatementsTryBlockFragment fragment); + void visit(TokensFragment fragment); +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/LineNumberTokensFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/LineNumberTokensFragment.java new file mode 100644 index 00000000..10187289 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/LineNumberTokensFragment.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.model.fragment.FixedFragment; +import org.jd.core.v1.model.token.AbstractNopTokenVisitor; +import org.jd.core.v1.model.token.LineNumberToken; +import org.jd.core.v1.model.token.NewLineToken; +import org.jd.core.v1.model.token.Token; + +import java.util.Arrays; +import java.util.List; + +public class LineNumberTokensFragment extends FixedFragment implements JavaFragment { + protected List tokens; + + public LineNumberTokensFragment(Token... tokens) { + this(Arrays.asList(tokens)); + } + + public LineNumberTokensFragment(List tokens) { + super(searchFirstLineNumber(tokens), searchLastLineNumber(tokens)); + assert firstLineNumber != Printer.UNKNOWN_LINE_NUMBER : "Uses 'TokensFragment' instead"; + this.tokens = tokens; + } + + public List getTokens() { + return tokens; + } + + protected static int searchFirstLineNumber(List tokens) { + SearchLineNumberVisitor visitor = new SearchLineNumberVisitor(); + + for (Token token : tokens) { + token.accept(visitor); + + if (visitor.lineNumber != Printer.UNKNOWN_LINE_NUMBER) { + return visitor.lineNumber - visitor.newLineCounter; + } + } + + return Printer.UNKNOWN_LINE_NUMBER; + } + + protected static int searchLastLineNumber(List tokens) { + SearchLineNumberVisitor visitor = new SearchLineNumberVisitor(); + int index = tokens.size(); + + while (index-- > 0) { + tokens.get(index).accept(visitor); + + if (visitor.lineNumber != Printer.UNKNOWN_LINE_NUMBER) { + return visitor.lineNumber + visitor.newLineCounter; + } + } + + return Printer.UNKNOWN_LINE_NUMBER; + } + + protected static class SearchLineNumberVisitor extends AbstractNopTokenVisitor { + public int lineNumber; + public int newLineCounter; + + public void reset() { + this.lineNumber = Printer.UNKNOWN_LINE_NUMBER; + this.newLineCounter = 0; + } + + @Override + public void visit(LineNumberToken token) { + lineNumber = token.getLineNumber(); + } + + @Override + public void visit(NewLineToken token) { + newLineCounter++; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/SpaceSpacerFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/SpaceSpacerFragment.java new file mode 100644 index 00000000..8f61c982 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/SpaceSpacerFragment.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public class SpaceSpacerFragment extends SpacerFragment implements JavaFragment { + + public SpaceSpacerFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/SpacerBetweenMembersFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/SpacerBetweenMembersFragment.java new file mode 100644 index 00000000..96a2b7b3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/SpacerBetweenMembersFragment.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.SpacerBetweenMovableBlocksFragment; + +public class SpacerBetweenMembersFragment extends SpacerBetweenMovableBlocksFragment implements JavaFragment { + + public SpacerBetweenMembersFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/SpacerFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/SpacerFragment.java new file mode 100644 index 00000000..20e48137 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/SpacerFragment.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.FlexibleFragment; + +public class SpacerFragment extends FlexibleFragment implements JavaFragment { + public SpacerFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartBlockFragment.java new file mode 100644 index 00000000..925bbbba --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartBlockFragment.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.StartFlexibleBlockFragment; + +public class StartBlockFragment extends StartFlexibleBlockFragment implements JavaFragment { + protected EndBlockFragment end; + + public StartBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public EndBlockFragment getEndArrayInitializerBlockFragment() { + return end; + } + + public void setEndArrayInitializerBlockFragment(EndBlockFragment end) { + this.end = end; + } + + public void setLineCount(int lineCount) { + this.lineCount = lineCount; + } + + @Override + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + + if (!force) { + // Update end body fragment + if ((lineCount == 1) && (end.getLineCount() == 0)) { + end.setLineCount(lineCount); + } + } + + return true; + } else { + return false; + } + } + + @Override + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + + if (!force) { + // Update end body fragment + if (lineCount == 1) { + end.setLineCount(lineCount); + } + } + + return true; + } else { + return false; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartBodyFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartBodyFragment.java new file mode 100644 index 00000000..42eb23b6 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartBodyFragment.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.StartFlexibleBlockFragment; + +public class StartBodyFragment extends StartFlexibleBlockFragment implements JavaFragment { + protected EndBodyFragment end; + + public StartBodyFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public EndBodyFragment getEndBodyFragment() { + return end; + } + + void setEndBodyFragment(EndBodyFragment end) { + this.end = end; + } + + public void setLineCount(int lineCount) { + this.lineCount = lineCount; + } + + @Override + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + + if (!force) { + // Update end body fragment + if ((lineCount == 1) && (end.getLineCount() == 0)) { + end.setLineCount(lineCount); + } + } + + return true; + } else { + return false; + } + } + + @Override + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + + if (!force) { + // Update end body fragment + if (lineCount == 1) { + end.setLineCount(lineCount); + } + } + + return true; + } else { + return false; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartMovableJavaBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartMovableJavaBlockFragment.java new file mode 100644 index 00000000..8bd073c3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartMovableJavaBlockFragment.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.StartMovableBlockFragment; + +public class StartMovableJavaBlockFragment extends StartMovableBlockFragment implements JavaFragment { + public static final StartMovableJavaBlockFragment START_MOVABLE_TYPE_BLOCK = new StartMovableJavaBlockFragment(1); + public static final StartMovableJavaBlockFragment START_MOVABLE_FIELD_BLOCK = new StartMovableJavaBlockFragment(2); + public static final StartMovableJavaBlockFragment START_MOVABLE_METHOD_BLOCK = new StartMovableJavaBlockFragment(3); + + protected StartMovableJavaBlockFragment(int type) { + super(type); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartSingleStatementBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartSingleStatementBlockFragment.java new file mode 100644 index 00000000..b9a9aa3d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartSingleStatementBlockFragment.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.StartFlexibleBlockFragment; + +public class StartSingleStatementBlockFragment extends StartFlexibleBlockFragment implements JavaFragment { + protected EndSingleStatementBlockFragment end; + + public StartSingleStatementBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public void setLineCount(int lineCount) { + this.lineCount = lineCount; + } + + public EndSingleStatementBlockFragment getEndSingleStatementBlockFragment() { + return end; + } + + public void setEndSingleStatementBlockFragment(EndSingleStatementBlockFragment end) { + this.end = end; + } + + @Override + public boolean incLineCount(boolean force) { + if (lineCount < maximalLineCount) { + lineCount++; + + if (!force) { + // Update end body fragment + if (end.getLineCount() == 0) { + end.setLineCount(1); + } + } + + return true; + } else { + return false; + } + } + + @Override + public boolean decLineCount(boolean force) { + if (lineCount > minimalLineCount) { + lineCount--; + + if (!force) { + // Update end body fragment + if (lineCount == 1) { + end.setLineCount(1); + } + } + + return true; + } else { + return false; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsBlockFragment.java new file mode 100644 index 00000000..e3b04860 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsBlockFragment.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.model.fragment.FlexibleFragment; +import org.jd.core.v1.model.fragment.StartFlexibleBlockFragment; +import org.jd.core.v1.util.DefaultList; + +public class StartStatementsBlockFragment extends StartFlexibleBlockFragment implements JavaFragment { + protected Group group; + + public StartStatementsBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + this.group = new Group(this); + } + + public StartStatementsBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, Group group) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + this.group = group; + group.add(this); + } + + public Group getGroup() { + return group; + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } + + public static class Group { + protected DefaultList fragments = new DefaultList<>(); + protected int minimalLineCount = Integer.MAX_VALUE; + + Group(FlexibleFragment fragment) { + this.fragments.add(fragment); + } + + void add(FlexibleFragment fragment) { + fragments.add(fragment); + } + + public int getMinimalLineCount() { + if (minimalLineCount == Integer.MAX_VALUE) { + for (FlexibleFragment fragment : fragments) { + if (minimalLineCount > fragment.getLineCount()) { + minimalLineCount = fragment.getLineCount(); + } + } + } + return minimalLineCount; + } + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsDoWhileBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsDoWhileBlockFragment.java new file mode 100644 index 00000000..17efd3de --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsDoWhileBlockFragment.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public class StartStatementsDoWhileBlockFragment extends StartStatementsBlockFragment { + public StartStatementsDoWhileBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public StartStatementsDoWhileBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, Group group) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label, group); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteForBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteForBlockFragment.java new file mode 100644 index 00000000..80e14b4d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteForBlockFragment.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public class StartStatementsInfiniteForBlockFragment extends StartStatementsBlockFragment { + public StartStatementsInfiniteForBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public StartStatementsInfiniteForBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, Group group) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label, group); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteWhileBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteWhileBlockFragment.java new file mode 100644 index 00000000..4c9247b0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsInfiniteWhileBlockFragment.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public class StartStatementsInfiniteWhileBlockFragment extends StartStatementsBlockFragment { + public StartStatementsInfiniteWhileBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public StartStatementsInfiniteWhileBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, Group group) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label, group); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsTryBlockFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsTryBlockFragment.java new file mode 100644 index 00000000..d2cdaeb4 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/StartStatementsTryBlockFragment.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +public class StartStatementsTryBlockFragment extends StartStatementsBlockFragment { + public StartStatementsTryBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label); + } + + public StartStatementsTryBlockFragment(int minimalLineCount, int lineCount, int maximalLineCount, int weight, String label, Group group) { + super(minimalLineCount, lineCount, maximalLineCount, weight, label, group); + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javafragment/TokensFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/TokensFragment.java new file mode 100644 index 00000000..3a6dc520 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javafragment/TokensFragment.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javafragment; + +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.model.fragment.FlexibleFragment; +import org.jd.core.v1.model.token.*; + +import java.util.Arrays; +import java.util.List; + +import static org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.visitor.StatementVisitor.RETURN; + +public class TokensFragment extends FlexibleFragment implements JavaFragment { + public static final TokensFragment COMMA = new TokensFragment(TextToken.COMMA); + public static final TokensFragment SEMICOLON = new TokensFragment(TextToken.SEMICOLON); + public static final TokensFragment START_DECLARATION_OR_STATEMENT_BLOCK = new TokensFragment(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); + public static final TokensFragment END_DECLARATION_OR_STATEMENT_BLOCK = new TokensFragment(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + public static final TokensFragment END_DECLARATION_OR_STATEMENT_BLOCK_SEMICOLON = new TokensFragment(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK, TextToken.SEMICOLON); + public static final TokensFragment RETURN_SEMICOLON = new TokensFragment(RETURN, TextToken.SEMICOLON); + + protected List tokens; + + public TokensFragment(Token... tokens) { + this(Arrays.asList(tokens)); + } + + public TokensFragment(List tokens) { + this(getLineCount(tokens), tokens); + } + + protected TokensFragment(int lineCount, List tokens) { + super(lineCount, lineCount, lineCount, 0, "Tokens"); + this.tokens = tokens; + } + + public List getTokens() { + return tokens; + } + + protected static int getLineCount(List tokens) { + LineCountVisitor visitor = new LineCountVisitor(); + + for (Token token : tokens) { + token.accept(visitor); + } + + return visitor.lineCount; + } + + protected static class LineCountVisitor extends AbstractNopTokenVisitor { + public int lineCount = 0; + + @Override + public void visit(LineNumberToken token) { + lineCount++; + assert token.getLineNumber() == Printer.UNKNOWN_LINE_NUMBER : "LineNumberToken cannot have a known line number. Uses 'LineNumberTokensFragment' instead"; + } + } + + @Override + public void accept(JavaFragmentVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java new file mode 100644 index 00000000..91261fed --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax; + +import org.jd.core.v1.model.javasyntax.declaration.*; +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.reference.*; +import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.AbstractTypeVisitor; +import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.InnerObjectType; +import org.jd.core.v1.model.javasyntax.type.ObjectType; + +import java.util.List; + +public abstract class AbstractJavaSyntaxVisitor extends AbstractTypeVisitor implements DeclarationVisitor, ExpressionVisitor, ReferenceVisitor, StatementVisitor { + public void visit(CompilationUnit compilationUnit) { + compilationUnit.getTypeDeclarations().accept(this); + } + + @Override + public void visit(AnnotationDeclaration declaration) { + safeAccept(declaration.getAnnotationDeclarators()); + safeAccept(declaration.getBodyDeclaration()); + visit((TypeDeclaration) declaration); + } + + @Override + public void visit(ArrayVariableInitializer declaration) { + acceptListDeclaration(declaration); + } + + @Override + public void visit(BodyDeclaration declaration) { + safeAccept(declaration.getMemberDeclarations()); + } + + @Override + public void visit(ClassDeclaration declaration) { + safeAccept(declaration.getSuperType()); + visit((InterfaceDeclaration) declaration); + } + + @Override public void visit(CommentStatement statement) {} + + @Override public void visit(CommentExpression expression) {} + + @Override + public void visit(ConstructorInvocationExpression expression) { + safeAccept(expression.getParameters()); + expression.getType().accept(this); + } + + @Override + public void visit(ConstructorDeclaration declaration) { + safeAccept(declaration.getAnnotationReferences()); + safeAccept(declaration.getFormalParameters()); + safeAccept(declaration.getExceptions()); + safeAccept(declaration.getStatements()); + } + + @Override + public void visit(EnumDeclaration declaration) { + visit((TypeDeclaration) declaration); + safeAccept(declaration.getInterfaces()); + safeAcceptListDeclaration(declaration.getConstants()); + safeAccept(declaration.getBodyDeclaration()); + } + + @Override + public void visit(EnumDeclaration.Constant declaration) { + safeAccept(declaration.getAnnotationReferences()); + safeAccept(declaration.getArguments()); + safeAccept(declaration.getBodyDeclaration()); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(Expressions list) { + acceptListExpression(list); + } + + @Override + public void visit(ExpressionVariableInitializer declaration) { + safeAccept(declaration.getExpression()); + } + + @Override + public void visit(FieldDeclaration declaration) { + safeAccept(declaration.getAnnotationReferences()); + declaration.getType().accept(this); + declaration.getFieldDeclarators().accept(this); + } + + @Override + public void visit(FieldDeclarator declaration) { + safeAccept(declaration.getVariableInitializer()); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(FieldDeclarators list) { + acceptListDeclaration((List)list); + } + + @Override + public void visit(FormalParameter declaration) { + safeAccept(declaration.getAnnotationReferences()); + declaration.getType().accept(this); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(FormalParameters list) { + acceptListDeclaration(list); + } + + @Override + public void visit(InstanceInitializerDeclaration declaration) { + safeAccept(declaration.getStatements()); + } + + @Override + public void visit(InterfaceDeclaration declaration) { + safeAccept(declaration.getInterfaces()); + safeAccept(declaration.getBodyDeclaration()); + visit((TypeDeclaration) declaration); + } + + @Override + public void visit(LocalVariableDeclaration declaration) { + declaration.getType().accept(this); + declaration.getLocalVariableDeclarators().accept(this); + } + + @Override + public void visit(LocalVariableDeclarator declarator) { + safeAccept(declarator.getVariableInitializer()); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(LocalVariableDeclarators declarators) { + acceptListDeclaration(declarators); + } + + @Override + public void visit(MethodDeclaration declaration) { + safeAccept(declaration.getAnnotationReferences()); + declaration.getReturnedType().accept(this); + safeAccept(declaration.getFormalParameters()); + safeAccept(declaration.getExceptionTypes()); + safeAccept(declaration.getStatements()); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(MemberDeclarations declarations) { + acceptListDeclaration(declarations); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(TypeDeclarations list) { + acceptListDeclaration(list); + } + + @Override + public void visit(ArrayExpression expression) { + expression.getType().accept(this); + expression.getExpression().accept(this); + expression.getIndex().accept(this); + } + + @Override + public void visit(BinaryOperatorExpression expression) { + expression.getLeftExpression().accept(this); + expression.getRightExpression().accept(this); + } + + @Override + public void visit(BooleanExpression expression) {} + + @Override + public void visit(CastExpression expression) { + expression.getType().accept(this); + expression.getExpression().accept(this); + } + + @Override + public void visit(ConstructorReferenceExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(DoubleConstantExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(EnumConstantReferenceExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(FieldReferenceExpression expression) { + safeAccept(expression.getExpression()); + expression.getType().accept(this); + } + + @Override + public void visit(FloatConstantExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(IntegerConstantExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(InstanceOfExpression expression) { + expression.getExpression().accept(this); + expression.getType().accept(this); + } + + @Override + public void visit(LambdaFormalParametersExpression expression) { + safeAccept(expression.getParameters()); + expression.getStatements().accept(this); + } + + @Override + public void visit(LambdaIdentifiersExpression expression) { + safeAccept(expression.getStatements()); + } + + @Override public void visit(LengthExpression expression) { + expression.getExpression().accept(this); + } + + @Override + public void visit(LocalVariableReferenceExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(LongConstantExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(MethodInvocationExpression expression) { + safeAccept(expression.getParameters()); + expression.getExpression().accept(this); + } + + @Override + public void visit(MethodReferenceExpression expression) { + expression.getExpression().accept(this); + } + + @Override + public void visit(NewArray expression) { + expression.getType().accept(this); + safeAccept(expression.getDimensionExpressionList()); + } + + @Override + public void visit(NewExpression expression) { + safeAccept(expression.getNonWildcardTypeArguments()); + expression.getType().accept(this); + safeAccept(expression.getParameters()); + // safeAccept(expression.getBodyDeclaration()); + } + + @Override + public void visit(NewInitializedArray expression) { + expression.getType().accept(this); + safeAccept(expression.getArrayInitializer()); + } + + @Override + public void visit(NewInnerExpression expression) { + expression.getExpression().accept(this); + safeAccept(expression.getNonWildcardTypeArguments()); + expression.getType().accept(this); + safeAccept(expression.getParameters()); + //safeAccept(expression.getBodyDeclaration()); + } + + @Override + public void visit(NullExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(TypeReferenceDotClassExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(ObjectTypeReferenceExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(ParenthesesExpression expression) { + expression.getExpression().accept(this); + } + + @Override + public void visit(PostOperatorExpression expression) { + expression.getExpression().accept(this); + } + + @Override + public void visit(PreOperatorExpression expression) { + expression.getExpression().accept(this); + } + + @Override + public void visit(StringConstantExpression expression) {} + + @Override + public void visit(SuperConstructorInvocationExpression expression) { + safeAccept(expression.getParameters()); + expression.getType().accept(this); + } + + @Override + public void visit(SuperExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(TernaryOperatorExpression expression) { + expression.getCondition().accept(this); + expression.getExpressionTrue().accept(this); + expression.getExpressionFalse().accept(this); + } + + @Override + public void visit(ThisExpression expression) { + expression.getType().accept(this); + } + + @Override + public void visit(AnnotationReference reference) { + safeAccept(reference.getElementValue()); + safeAccept(reference.getElementValuePairs()); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(AnnotationReferences list) { + acceptListReference(list); + } + + @Override + public void visit(ExpressionElementValue reference) { + reference.getExpression().accept(this); + } + + @Override + public void visit(ElementValueArrayInitializerElementValue reference) { + safeAccept(reference.getElementValueArrayInitializer()); + } + + @Override + public void visit(AnnotationElementValue reference) { + safeAccept(reference.getElementValue()); + safeAccept(reference.getElementValuePairs()); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(ElementValues list) { + acceptListReference(list); + } + + @Override + public void visit(ElementValuePair reference) { + reference.getElementValue().accept(this); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(ElementValuePairs list) { + acceptListReference(list); + } + + @Override + public void visit(ObjectReference reference) { + visit((ObjectType) reference); + } + + @Override public void visit(InnerObjectReference reference) { + visit((InnerObjectType) reference); + } + + @Override + public void visit(AssertStatement statement) { + statement.getCondition().accept(this); + safeAccept(statement.getMessage()); + } + + @Override + public void visit(BreakStatement statement) {} + + @Override public void visit(ByteCodeStatement statement) {} + + @Override + public void visit(ContinueStatement statement) {} + + @Override + public void visit(DoWhileStatement statement) { + safeAccept(statement.getCondition()); + safeAccept(statement.getStatements()); + } + + @Override + public void visit(ExpressionStatement statement) { + statement.getExpression().accept(this); + } + + @Override + public void visit(ForEachStatement statement) { + statement.getType().accept(this); + statement.getExpression().accept(this); + safeAccept(statement.getStatements()); + } + + @Override + public void visit(ForStatement statement) { + safeAccept(statement.getDeclaration()); + safeAccept(statement.getInit()); + safeAccept(statement.getCondition()); + safeAccept(statement.getUpdate()); + safeAccept(statement.getStatements()); + } + + @Override + public void visit(IfStatement statement) { + statement.getCondition().accept(this); + safeAccept(statement.getStatements()); + } + + @Override + public void visit(IfElseStatement statement) { + statement.getCondition().accept(this); + safeAccept(statement.getStatements()); + statement.getElseStatements().accept(this); + } + + @Override + public void visit(LabelStatement statement) { + safeAccept(statement.getStatement()); + } + + @Override + public void visit(LambdaExpressionStatement statement) { + statement.getExpression().accept(this); + } + + @Override + public void visit(LocalVariableDeclarationStatement statement) { + visit((LocalVariableDeclaration) statement); + } + + @Override public void visit(ReturnExpressionStatement statement) { + statement.getExpression().accept(this); + } + + @Override + public void visit(ReturnStatement statement) {} + + @Override + @SuppressWarnings("unchecked") + public void visit(Statements list) { + acceptListStatement(list); + } + + @Override + public void visit(SwitchStatement statement) { + statement.getCondition().accept(this); + acceptListStatement(statement.getBlocks()); + } + + @Override + public void visit(SwitchStatement.DefaultLabel statement) {} + + @Override + public void visit(SwitchStatement.ExpressionLabel statement) { + statement.getExpression().accept(this); + } + + @Override + public void visit(SwitchStatement.LabelBlock statement) { + statement.getLabel().accept(this); + statement.getStatements().accept(this); + } + + @Override + public void visit(SwitchStatement.MultiLabelsBlock statement) { + safeAcceptListStatement(statement.getLabels()); + statement.getStatements().accept(this); + } + + @Override + public void visit(SynchronizedStatement statement) { + statement.getMonitor().accept(this); + safeAccept(statement.getStatements()); + } + + @Override + public void visit(ThrowStatement statement) { + statement.getExpression().accept(this); + } + + @Override + public void visit(TryStatement statement) { + safeAcceptListStatement(statement.getResources()); + statement.getTryStatements().accept(this); + safeAcceptListStatement(statement.getCatchClauses()); + safeAccept(statement.getFinallyStatements()); + } + + @Override + public void visit(TryStatement.CatchClause statement) { + statement.getType().accept(this); + safeAccept(statement.getStatements()); + } + + @Override + public void visit(TryStatement.Resource statement) { + statement.getType().accept(this); + statement.getExpression().accept(this); + } + + @Override + public void visit(StaticInitializerDeclaration declaration) { + safeAccept(declaration.getStatements()); + } + + @Override + public void visit(TypeDeclarationStatement statement) { + statement.getTypeDeclaration().accept(this); + } + + @Override + public void visit(WhileStatement statement) { + statement.getCondition().accept(this); + safeAccept(statement.getStatements()); + } + + protected void visit(TypeDeclaration declaration) { + safeAccept(declaration.getAnnotationReferences()); + } + + protected void acceptListDeclaration(List list) { + for (Declaration declaration : list) + declaration.accept(this); + } + + protected void acceptListExpression(List list) { + for (Expression expression : list) + expression.accept(this); + } + + protected void acceptListReference(List list) { + for (Reference reference : list) + reference.accept(this); + } + + protected void acceptListStatement(List list) { + for (Statement statement : list) + statement.accept(this); + } + + protected void safeAccept(Declaration declaration) { + if (declaration != null) + declaration.accept(this); + } + + protected void safeAccept(BaseExpression expression) { + if (expression != null) + expression.accept(this); + } + + protected void safeAccept(Reference reference) { + if (reference != null) + reference.accept(this); + } + + protected void safeAccept(BaseStatement list) { + if (list != null) + list.accept(this); + } + + protected void safeAccept(BaseType list) { + if (list != null) + list.accept(this); + } + + protected void safeAcceptListDeclaration(List list) { + if (list != null) { + for (Declaration declaration : list) + declaration.accept(this); + } + } + + protected void safeAcceptListStatement(List list) { + if (list != null) { + for (Statement statement : list) + statement.accept(this); + } + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/CompilationUnit.java b/src/main/java/org/jd/core/v1/model/javasyntax/CompilationUnit.java new file mode 100644 index 00000000..588eebb2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/CompilationUnit.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax; + +import org.jd.core.v1.model.javasyntax.declaration.BaseTypeDeclaration; + +public class CompilationUnit { + protected BaseTypeDeclaration typeDeclarations; + + public CompilationUnit(BaseTypeDeclaration typeDeclarations) { + this.typeDeclarations = typeDeclarations; + } + + public BaseTypeDeclaration getTypeDeclarations() { + return typeDeclarations; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java new file mode 100644 index 00000000..77e159bb --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public abstract class AbstractNopDeclarationVisitor implements DeclarationVisitor { + @Override public void visit(AnnotationDeclaration declaration) {} + @Override public void visit(ArrayVariableInitializer declaration) {} + @Override public void visit(BodyDeclaration declaration) {} + @Override public void visit(ClassDeclaration declaration) {} + @Override public void visit(ConstructorDeclaration declaration) {} + @Override public void visit(EnumDeclaration declaration) {} + @Override public void visit(EnumDeclaration.Constant declaration) {} + @Override public void visit(ExpressionVariableInitializer declaration) {} + @Override public void visit(FieldDeclaration declaration) {} + @Override public void visit(FieldDeclarator declaration) {} + @Override public void visit(FieldDeclarators declarations) {} + @Override public void visit(FormalParameter declaration) {} + @Override public void visit(FormalParameters declarations) {} + @Override public void visit(InstanceInitializerDeclaration declaration) {} + @Override public void visit(InterfaceDeclaration declaration) {} + @Override public void visit(LocalVariableDeclaration declaration) {} + @Override public void visit(LocalVariableDeclarator declarator) {} + @Override public void visit(LocalVariableDeclarators declarators) {} + @Override public void visit(MemberDeclarations declarations) {} + @Override public void visit(MethodDeclaration declaration) {} + @Override public void visit(StaticInitializerDeclaration declaration) {} + @Override public void visit(TypeDeclarations declaration) {} +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java new file mode 100644 index 00000000..4566ed5f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; + +public class AnnotationDeclaration extends TypeDeclaration { + protected BaseFieldDeclarator annotationDeclarators; + protected BodyDeclaration bodyDeclaration; + + public AnnotationDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseFieldDeclarator annotationDeclarators, BodyDeclaration bodyDeclaration) { + super(annotationReferences, flags, internalName, name); + this.annotationDeclarators = annotationDeclarators; + this.bodyDeclaration = bodyDeclaration; + } + + public BaseFieldDeclarator getAnnotationDeclarators() { + return annotationDeclarators; + } + + public BodyDeclaration getBodyDeclaration() { + return bodyDeclaration; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "AnnotationDeclaration{" + internalName + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ArrayVariableInitializer.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ArrayVariableInitializer.java new file mode 100644 index 00000000..481d0321 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ArrayVariableInitializer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.util.DefaultList; + +public class ArrayVariableInitializer extends DefaultList implements VariableInitializer { + protected Type type; + + public ArrayVariableInitializer(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + @Override + public int getLineNumber() { + return isEmpty() ? 0 : get(0).getLineNumber(); + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFieldDeclarator.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFieldDeclarator.java new file mode 100644 index 00000000..833c3afa --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFieldDeclarator.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.Base; + +public interface BaseFieldDeclarator extends Declaration, Base { + void setFieldDeclaration(FieldDeclaration fieldDeclaration); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFormalParameter.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFormalParameter.java new file mode 100644 index 00000000..67f1c57c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseFormalParameter.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.Base; + +public interface BaseFormalParameter extends Declaration, Base {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseLocalVariableDeclarator.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseLocalVariableDeclarator.java new file mode 100644 index 00000000..b1722884 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseLocalVariableDeclarator.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.Base; + +public interface BaseLocalVariableDeclarator extends Declaration, Base { + int getLineNumber(); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java new file mode 100644 index 00000000..57034eff --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.Base; + +public interface BaseMemberDeclaration extends Declaration, Base { +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseTypeDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseTypeDeclaration.java new file mode 100644 index 00000000..385ea64b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseTypeDeclaration.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public interface BaseTypeDeclaration extends BaseMemberDeclaration { +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BodyDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BodyDeclaration.java new file mode 100644 index 00000000..dad65f66 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BodyDeclaration.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public class BodyDeclaration implements Declaration { + protected String internalTypeName; + protected BaseMemberDeclaration memberDeclarations; + + public BodyDeclaration(String internalTypeName, BaseMemberDeclaration memberDeclarations) { + this.internalTypeName = internalTypeName; + this.memberDeclarations = memberDeclarations; + } + + public String getInternalTypeName() { + return internalTypeName; + } + + public BaseMemberDeclaration getMemberDeclarations() { + return memberDeclarations; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java new file mode 100644 index 00000000..08397647 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class ClassDeclaration extends InterfaceDeclaration { + protected Type superType; + + public ClassDeclaration(int flags, String internalName, String name, BodyDeclaration bodyDeclaration) { + super(null, flags, internalName, name, null, null, bodyDeclaration); + } + + public ClassDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, Type superType, BaseType interfaces, BodyDeclaration bodyDeclaration) { + super(annotationReferences, flags, internalName, name, typeParameters, interfaces, bodyDeclaration); + this.superType = superType; + } + + public Type getSuperType() { + return superType; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ClassDeclaration{" + internalName + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java new file mode 100644 index 00000000..0621ab1f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; +import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; + +public class ConstructorDeclaration implements MemberDeclaration { + protected BaseAnnotationReference annotationReferences; + protected int flags; + protected BaseTypeParameter typeParameters; + protected BaseFormalParameter formalParameters; + protected BaseType exceptions; + protected String descriptor; + protected BaseStatement statements; + + public ConstructorDeclaration(int flags, BaseFormalParameter formalParameters, String descriptor, BaseStatement statements) { + this.flags = flags; + this.formalParameters = formalParameters; + this.descriptor = descriptor; + this.statements = statements; + } + + public ConstructorDeclaration(BaseAnnotationReference annotationReferences, int flags, BaseTypeParameter typeParameters, BaseFormalParameter formalParameters, BaseType exceptions, String descriptor, BaseStatement statements) { + this.annotationReferences = annotationReferences; + this.flags = flags; + this.typeParameters = typeParameters; + this.formalParameters = formalParameters; + this.exceptions = exceptions; + this.descriptor = descriptor; + this.statements = statements; + } + + public int getFlags() { + return flags; + } + + public BaseAnnotationReference getAnnotationReferences() { + return annotationReferences; + } + + public BaseTypeParameter getTypeParameters() { + return typeParameters; + } + + public BaseFormalParameter getFormalParameters() { + return formalParameters; + } + + public BaseType getExceptions() { + return exceptions; + } + + public String getDescriptor() { + return descriptor; + } + + public BaseStatement getStatements() { + return statements; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ConstructorDeclaration{" + descriptor + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java new file mode 100644 index 00000000..96f7def5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public interface Declaration { + public final static int FLAG_PUBLIC = 0x0001; + public final static int FLAG_PRIVATE = 0x0002; + public final static int FLAG_PROTECTED = 0x0004; + public final static int FLAG_STATIC = 0x0008; + public final static int FLAG_FINAL = 0x0010; + public final static int FLAG_BRIDGE = 0x0040; + public final static int FLAG_VARARGS = 0x0080; + public final static int FLAG_NATIVE = 0x0100; + public final static int FLAG_INTERFACE = 0x0200; + public final static int FLAG_ABSTRACT = 0x0400; + public final static int FLAG_SYNTHETIC = 0x1000; + public final static int FLAG_ANNOTATION = 0x2000; + public final static int FLAG_ENUM = 0x4000; + + void accept(DeclarationVisitor visitor); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java new file mode 100644 index 00000000..51da1540 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public interface DeclarationVisitor { + void visit(AnnotationDeclaration declaration); + void visit(ArrayVariableInitializer declaration); + void visit(BodyDeclaration declaration); + void visit(ClassDeclaration declaration); + void visit(ConstructorDeclaration declaration); + void visit(EnumDeclaration declaration); + void visit(EnumDeclaration.Constant declaration); + void visit(ExpressionVariableInitializer declaration); + void visit(FieldDeclaration declaration); + void visit(FieldDeclarator declaration); + void visit(FieldDeclarators declarations); + void visit(FormalParameter declaration); + void visit(FormalParameters declarations); + void visit(InstanceInitializerDeclaration declaration); + void visit(InterfaceDeclaration declaration); + void visit(LocalVariableDeclaration declaration); + void visit(LocalVariableDeclarator declarator); + void visit(LocalVariableDeclarators declarators); + void visit(MethodDeclaration declaration); + void visit(MemberDeclarations declarations); + void visit(StaticInitializerDeclaration declaration); + void visit(TypeDeclarations declarations); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java new file mode 100644 index 00000000..2e856d5b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.type.BaseType; + +import java.util.List; + +public class EnumDeclaration extends TypeDeclaration { + protected BaseType interfaces; + protected List constants; + protected BodyDeclaration bodyDeclaration; + + public EnumDeclaration(int flags, String internalName, String name, List constants, BodyDeclaration bodyDeclaration) { + super(null, flags, internalName, name); + this.constants = constants; + this.bodyDeclaration = bodyDeclaration; + } + + public EnumDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseType interfaces, List constants, BodyDeclaration bodyDeclaration) { + super(annotationReferences, flags, internalName, name); + this.interfaces = interfaces; + this.constants = constants; + this.bodyDeclaration = bodyDeclaration; + } + + public BaseType getInterfaces() { + return interfaces; + } + + public List getConstants() { + return constants; + } + + public BodyDeclaration getBodyDeclaration() { + return bodyDeclaration; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "EnumDeclaration{" + internalName + "}"; + } + + public static class Constant implements Declaration { + protected int lineNumber; + protected BaseAnnotationReference annotationReferences; + protected String name; + protected BaseExpression arguments; + protected BodyDeclaration bodyDeclaration; + + public Constant(String name) { + this.name = name; + } + + public Constant(int lineNumber, String name) { + this.lineNumber = lineNumber; + this.name = name; + } + + public Constant(String name, BaseExpression arguments) { + this.name = name; + this.arguments = arguments; + } + + public Constant(int lineNumber, String name, BaseExpression arguments) { + this.lineNumber = lineNumber; + this.name = name; + this.arguments = arguments; + } + + public Constant(int lineNumber, String name, BaseExpression arguments, BodyDeclaration bodyDeclaration) { + this.lineNumber = lineNumber; + this.name = name; + this.arguments = arguments; + this.bodyDeclaration = bodyDeclaration; + } + + public Constant(int lineNumber, BaseAnnotationReference annotationReferences, String name, BaseExpression arguments, BodyDeclaration bodyDeclaration) { + this.lineNumber = lineNumber; + this.annotationReferences = annotationReferences; + this.name = name; + this.arguments = arguments; + this.bodyDeclaration = bodyDeclaration; + } + + public int getLineNumber() { + return lineNumber; + } + + public BaseAnnotationReference getAnnotationReferences() { + return annotationReferences; + } + + public String getName() { + return name; + } + + public BaseExpression getArguments() { + return arguments; + } + + public BodyDeclaration getBodyDeclaration() { + return bodyDeclaration; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java new file mode 100644 index 00000000..3b0e02ce --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class ExpressionVariableInitializer implements VariableInitializer { + protected Expression expression; + + public ExpressionVariableInitializer(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + @Override + public int getLineNumber() { + return expression.getLineNumber(); + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ExpressionVariableInitializer)) return false; + + ExpressionVariableInitializer that = (ExpressionVariableInitializer) o; + + if (expression != null ? !expression.equals(that.expression) : that.expression != null) return false; + + return true; + } + + @Override + public int hashCode() { + return expression != null ? expression.hashCode() : 0; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java new file mode 100644 index 00000000..98be4071 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class FieldDeclaration implements MemberDeclaration { + protected BaseAnnotationReference annotationReferences; + protected int flags; + protected Type type; + protected BaseFieldDeclarator fieldDeclarators; + + public FieldDeclaration(int flags, Type type, BaseFieldDeclarator fieldDeclarators) { + this.flags = flags; + this.type = type; + this.fieldDeclarators = fieldDeclarators; + fieldDeclarators.setFieldDeclaration(this); + } + + public FieldDeclaration(BaseAnnotationReference annotationReferences, int flags, Type type, BaseFieldDeclarator fieldDeclarators) { + this.flags = flags; + this.annotationReferences = annotationReferences; + this.type = type; + this.fieldDeclarators = fieldDeclarators; + fieldDeclarators.setFieldDeclaration(this); + } + + public int getFlags() { + return flags; + } + + public BaseAnnotationReference getAnnotationReferences() { + return annotationReferences; + } + + public Type getType() { + return type; + } + + public BaseFieldDeclarator getFieldDeclarators() { + return fieldDeclarators; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof FieldDeclaration)) return false; + + FieldDeclaration that = (FieldDeclaration) o; + + if (flags != that.flags) return false; + if (annotationReferences != null ? !annotationReferences.equals(that.annotationReferences) : that.annotationReferences != null) + return false; + if (!fieldDeclarators.equals(that.fieldDeclarators)) return false; + if (!type.equals(that.type)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = flags; + result = 31 * result + (annotationReferences != null ? annotationReferences.hashCode() : 0); + result = 31 * result + type.hashCode(); + result = 31 * result + fieldDeclarators.hashCode(); + return result; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "FieldDeclaration{" + type + " " + fieldDeclarators + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java new file mode 100644 index 00000000..04640ba2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public class FieldDeclarator implements BaseFieldDeclarator { + protected FieldDeclaration fieldDeclaration; + protected String name; + protected int dimension; + protected VariableInitializer variableInitializer; + + public FieldDeclarator(String name) { + this.name = name; + } + + public FieldDeclarator(String name, VariableInitializer variableInitializer) { + this.name = name; + this.variableInitializer = variableInitializer; + } + + public FieldDeclarator(String name, int dimension, VariableInitializer variableInitializer) { + this.name = name; + this.dimension = dimension; + this.variableInitializer = variableInitializer; + } + + @Override + public void setFieldDeclaration(FieldDeclaration fieldDeclaration) { + this.fieldDeclaration = fieldDeclaration; + } + + public FieldDeclaration getFieldDeclaration() { + return fieldDeclaration; + } + + public String getName() { + return name; + } + + public int getDimension() { + return dimension; + } + + public VariableInitializer getVariableInitializer() { + return variableInitializer; + } + + public void setVariableInitializer(VariableInitializer variableInitializer) { + this.variableInitializer = variableInitializer; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof FieldDeclarator)) return false; + + FieldDeclarator that = (FieldDeclarator) o; + + if (dimension != that.dimension) return false; + if (!name.equals(that.name)) return false; + if (variableInitializer != null ? !variableInitializer.equals(that.variableInitializer) : that.variableInitializer != null) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + dimension; + result = 31 * result + (variableInitializer != null ? variableInitializer.hashCode() : 0); + return result; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "FieldDeclarator{" + name + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java new file mode 100644 index 00000000..2a42f9f0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class FieldDeclarators extends DefaultList implements BaseFieldDeclarator { + public FieldDeclarators() {} + + public FieldDeclarators(int capacity) { + super(capacity); + } + + public FieldDeclarators(Collection collection) { + super(collection); + assert (collection != null) && (collection.size() > 1) : "Uses 'FieldDeclarator' instead"; + } + + @SuppressWarnings("unchecked") + public FieldDeclarators(T declarator, T... declarators) { + super(declarator, declarators); + assert (declarators != null) && (declarators.length > 0) : "Uses 'FieldDeclarator' instead"; + } + + @Override + public void setFieldDeclaration(FieldDeclaration fieldDeclaration) { + for (FieldDeclarator fieldDeclarator : this) { + fieldDeclarator.setFieldDeclaration(fieldDeclaration); + } + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameter.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameter.java new file mode 100644 index 00000000..e20d5a34 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameter.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class FormalParameter implements BaseFormalParameter { + protected BaseAnnotationReference annotationReferences; + protected boolean fina1; + protected Type type; + protected boolean varargs; + protected String name; + + public FormalParameter(Type type, String name) { + this.type = type; + this.name = name; + } + + public FormalParameter(BaseAnnotationReference annotationReferences, Type type, String name) { + this.annotationReferences = annotationReferences; + this.type = type; + this.name = name; + } + + public FormalParameter(Type type, boolean varargs, String name) { + this.type = type; + this.varargs = varargs; + this.name = name; + } + + public FormalParameter(BaseAnnotationReference annotationReferences, Type type, boolean varargs, String name) { + this.annotationReferences = annotationReferences; + this.type = type; + this.varargs = varargs; + this.name = name; + } + + public BaseAnnotationReference getAnnotationReferences() { + return annotationReferences; + } + + public boolean isFinal() { + return fina1; + } + + public void setFinal(boolean fina1) { + this.fina1 = fina1; + } + + public Type getType() { + return type; + } + + public boolean isVarargs() { + return varargs; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + String s = "FormalParameter{"; + + if (annotationReferences != null) + s += annotationReferences + " "; + + if (varargs) + s += type.createType(type.getDimension()-1) + "... "; + else + s += type + " "; + + return s + name + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java new file mode 100644 index 00000000..3ab7318c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class FormalParameters extends DefaultList implements BaseFormalParameter { + public FormalParameters() {} + + public FormalParameters(Collection collection) { + super(collection); + assert (collection != null) && (collection.size() > 1) : "Uses 'FormalParameter' instead"; + } + + @SuppressWarnings("unchecked") + public FormalParameters(T parameter, T... parameters) { + super(parameter, parameters); + assert (parameters != null) && (parameters.length > 0) : "Uses 'FormalParameter' instead"; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InstanceInitializerDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InstanceInitializerDeclaration.java new file mode 100644 index 00000000..307a4ccb --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InstanceInitializerDeclaration.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; + +public class InstanceInitializerDeclaration implements MemberDeclaration { + protected String descriptor; + protected BaseStatement statements; + + public InstanceInitializerDeclaration(String descriptor, BaseStatement statements) { + this.descriptor = descriptor; + this.statements = statements; + } + + public String getDescriptor() { + return descriptor; + } + + public BaseStatement getStatements() { + return statements; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "InstanceInitializerDeclaration{}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java new file mode 100644 index 00000000..f8db8d46 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; + +public class InterfaceDeclaration extends TypeDeclaration { + protected BaseTypeParameter typeParameters; + protected BaseType interfaces; + protected BodyDeclaration bodyDeclaration; + + public InterfaceDeclaration(int flags, String internalName, String name, BaseType interfaces) { + super(null, flags, internalName, name); + this.interfaces = interfaces; + } + + public InterfaceDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, BaseType interfaces, BodyDeclaration bodyDeclaration) { + super(annotationReferences, flags, internalName, name); + this.typeParameters = typeParameters; + this.interfaces = interfaces; + this.bodyDeclaration = bodyDeclaration; + } + + public BaseTypeParameter getTypeParameters() { + return typeParameters; + } + + public BaseType getInterfaces() { + return interfaces; + } + + public BodyDeclaration getBodyDeclaration() { + return bodyDeclaration; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "InterfaceDeclaration{" + internalName + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclaration.java new file mode 100644 index 00000000..870e3fb8 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclaration.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class LocalVariableDeclaration implements Declaration { + protected boolean fina1 = false; + protected Type type; + protected BaseLocalVariableDeclarator localVariableDeclarators; + + public LocalVariableDeclaration(Type type, BaseLocalVariableDeclarator localVariableDeclarators) { + this.type = type; + this.localVariableDeclarators = localVariableDeclarators; + } + + public boolean isFinal() { + return fina1; + } + + public void setFinal(boolean fina1) { + this.fina1 = fina1; + } + + public Type getType() { + return type; + } + + public BaseLocalVariableDeclarator getLocalVariableDeclarators() { + return localVariableDeclarators; + } + + public void setLocalVariableDeclarators(BaseLocalVariableDeclarator localVariableDeclarators) { + this.localVariableDeclarators = localVariableDeclarators; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarator.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarator.java new file mode 100644 index 00000000..c6b55804 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarator.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public class LocalVariableDeclarator implements BaseLocalVariableDeclarator { + protected int lineNumber; + protected String name; + protected int dimension; + protected VariableInitializer variableInitializer; + + public LocalVariableDeclarator(String name) { + this.name = name; + } + + public LocalVariableDeclarator(int lineNumber, String name) { + this.lineNumber = lineNumber; + this.name = name; + } + + public LocalVariableDeclarator(String name, int dimension) { + this.name = name; + this.dimension = dimension; + } + + public LocalVariableDeclarator(String name, VariableInitializer variableInitializer) { + this.name = name; + this.variableInitializer = variableInitializer; + } + + public LocalVariableDeclarator(int lineNumber, String name, VariableInitializer variableInitializer) { + this.lineNumber = lineNumber; + this.name = name; + this.variableInitializer = variableInitializer; + } + + public LocalVariableDeclarator(String name, int dimension, VariableInitializer variableInitializer) { + this.name = name; + this.dimension = dimension; + this.variableInitializer = variableInitializer; + } + + public LocalVariableDeclarator(int lineNumber, String name, int dimension, VariableInitializer variableInitializer) { + this.lineNumber = lineNumber; + this.name = name; + this.dimension = dimension; + this.variableInitializer = variableInitializer; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getDimension() { + return dimension; + } + + public void setDimension(int dimension) { + this.dimension = dimension; + } + + @Override + public int getLineNumber() { + return lineNumber; + } + + public VariableInitializer getVariableInitializer() { + return variableInitializer; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LocalVariableDeclarator{name=" + name + ", dimension" + dimension + ", variableInitializer=" + variableInitializer + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java new file mode 100644 index 00000000..f2d3f388 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class LocalVariableDeclarators extends DefaultList implements BaseLocalVariableDeclarator { + + public LocalVariableDeclarators() {} + + public LocalVariableDeclarators(int capacity) { + super(capacity); + } + + public LocalVariableDeclarators(Collection collection) { + super(collection); + assert (collection != null) && (collection.size() > 1) : "Uses 'LocalVariableDeclarator' instead"; + } + + @Override + public int getLineNumber() { + return isEmpty() ? 0 : get(0).getLineNumber(); + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclaration.java new file mode 100644 index 00000000..6d35973d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclaration.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public interface MemberDeclaration extends BaseMemberDeclaration { +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java new file mode 100644 index 00000000..e6722e55 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class MemberDeclarations extends DefaultList implements BaseMemberDeclaration { + public MemberDeclarations() {} + + public MemberDeclarations(int capacity) { + super(capacity); + } + + public MemberDeclarations(Collection collection) { + super(collection); + assert (collection != null) && (collection.size() > 1) : "Uses 'MemberDeclaration' implementation instead"; + } + + @SuppressWarnings("unchecked") + public MemberDeclarations(T declaration, T... declarations) { + super(declaration, declarations); + assert (declarations != null) && (declarations.length > 0) : "Uses 'MemberDeclaration' implementation instead"; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MethodDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MethodDeclaration.java new file mode 100644 index 00000000..c666d0b5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MethodDeclaration.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.reference.ElementValue; +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; +import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class MethodDeclaration implements MemberDeclaration { + protected BaseAnnotationReference annotationReferences; + protected int flags; + protected String name; + protected BaseTypeParameter typeParameters; + protected Type returnedType; + protected BaseFormalParameter formalParameters; + protected BaseType exceptionTypes; + protected String descriptor; + protected BaseStatement statements; + protected ElementValue defaultAnnotationValue; + + public MethodDeclaration(int flags, String name, Type returnedType, String descriptor) { + this.flags = flags; + this.name = name; + this.returnedType = returnedType; + this.descriptor = descriptor; + } + + public MethodDeclaration(int flags, String name, Type returnedType, String descriptor, BaseStatement statements) { + this.flags = flags; + this.name = name; + this.returnedType = returnedType; + this.descriptor = descriptor; + this.statements = statements; + } + + public MethodDeclaration(int flags, String name, Type returnedType, String descriptor, ElementValue defaultAnnotationValue) { + this.flags = flags; + this.name = name; + this.returnedType = returnedType; + this.descriptor = descriptor; + this.defaultAnnotationValue = defaultAnnotationValue; + } + + public MethodDeclaration(int flags, String name, Type returnedType, BaseFormalParameter formalParameters, String descriptor, BaseStatement statements) { + this.flags = flags; + this.name = name; + this.returnedType = returnedType; + this.formalParameters = formalParameters; + this.descriptor = descriptor; + this.statements = statements; + } + + public MethodDeclaration(int flags, String name, Type returnedType, BaseFormalParameter formalParameters, String descriptor, ElementValue defaultAnnotationValue) { + this.flags = flags; + this.name = name; + this.returnedType = returnedType; + this.formalParameters = formalParameters; + this.descriptor = descriptor; + this.defaultAnnotationValue = defaultAnnotationValue; + } + + public MethodDeclaration(BaseAnnotationReference annotationReferences, int flags, String name, BaseTypeParameter typeParameters, Type returnedType, BaseFormalParameter formalParameters, BaseType exceptionTypes, String descriptor, BaseStatement statements, ElementValue defaultAnnotationValue) { + this.annotationReferences = annotationReferences; + this.flags = flags; + this.name = name; + this.typeParameters = typeParameters; + this.returnedType = returnedType; + this.formalParameters = formalParameters; + this.exceptionTypes = exceptionTypes; + this.descriptor = descriptor; + this.statements = statements; + this.defaultAnnotationValue = defaultAnnotationValue; + } + + public BaseAnnotationReference getAnnotationReferences() { + return annotationReferences; + } + + public int getFlags() { + return flags; + } + + public String getName() { + return name; + } + + public BaseTypeParameter getTypeParameters() { + return typeParameters; + } + + public Type getReturnedType() { + return returnedType; + } + + public BaseFormalParameter getFormalParameters() { + return formalParameters; + } + + public BaseType getExceptionTypes() { + return exceptionTypes; + } + + public String getDescriptor() { + return descriptor; + } + + public BaseStatement getStatements() { + return statements; + } + + public ElementValue getDefaultAnnotationValue() { + return defaultAnnotationValue; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "MethodDeclaration{" + name + " " + descriptor + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/StaticInitializerDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/StaticInitializerDeclaration.java new file mode 100644 index 00000000..24e0bd8a --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/StaticInitializerDeclaration.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; + +public class StaticInitializerDeclaration implements MemberDeclaration { + protected String descriptor; + protected BaseStatement statements; + + public StaticInitializerDeclaration(String descriptor, BaseStatement statements) { + this.descriptor = descriptor; + this.statements = statements; + } + + public String getDescriptor() { + return descriptor; + } + + public BaseStatement getStatements() { + return statements; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "StaticInitializerDeclaration{}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java new file mode 100644 index 00000000..f404bb14 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; + +public abstract class TypeDeclaration implements BaseTypeDeclaration, MemberDeclaration { + protected BaseAnnotationReference annotationReferences; + protected int flags; + protected String internalName; + protected String name; + + protected TypeDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name) { + this.annotationReferences = annotationReferences; + this.flags = flags; + this.internalName = internalName; + this.name = name; + } + + public BaseAnnotationReference getAnnotationReferences() { + return annotationReferences; + } + + public int getFlags() { + return flags; + } + + public String getInternalName() { + return internalName; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java new file mode 100644 index 00000000..2e300a92 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class TypeDeclarations extends DefaultList implements BaseTypeDeclaration { + public TypeDeclarations(Collection collection) { + super(collection); + assert (collection != null) && (collection.size() > 1) : "Uses 'TypeDeclaration' or sub class instead"; + } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java new file mode 100644 index 00000000..380d4e2d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +public interface VariableInitializer extends Declaration { + int getLineNumber(); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLambdaExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLambdaExpression.java new file mode 100644 index 00000000..71a374aa --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLambdaExpression.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; +import org.jd.core.v1.model.javasyntax.type.Type; + +public abstract class AbstractLambdaExpression extends AbstractLineNumberTypeExpression { + protected BaseStatement statements; + + protected AbstractLambdaExpression(Type type, BaseStatement statements) { + super(type); + this.statements = statements; + } + + protected AbstractLambdaExpression(int lineNumber, Type type, BaseStatement statements) { + super(lineNumber, type); + this.statements = statements; + } + + @Override + public int getPriority() { + return 17; + } + + public BaseStatement getStatements() { + return statements; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberExpression.java new file mode 100644 index 00000000..38b950bb --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberExpression.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +public abstract class AbstractLineNumberExpression implements Expression { + protected int lineNumber; + + protected AbstractLineNumberExpression() { + this.lineNumber = UNKNOWN_LINE_NUMBER; + } + + protected AbstractLineNumberExpression(int lineNumber) { + this.lineNumber = lineNumber; + } + + @Override + public int getLineNumber() { + return lineNumber; + } + + @Override + public int getPriority() { + return 0; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberTypeExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberTypeExpression.java new file mode 100644 index 00000000..59ea06ff --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractLineNumberTypeExpression.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public abstract class AbstractLineNumberTypeExpression extends AbstractLineNumberExpression { + protected Type type; + + protected AbstractLineNumberTypeExpression(Type type) { + this.type = type; + } + + protected AbstractLineNumberTypeExpression(int lineNumber, Type type) { + super(lineNumber); + this.type = type; + } + + @Override + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java new file mode 100644 index 00000000..903abc42 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +public abstract class AbstractNopExpressionVisitor implements ExpressionVisitor { + @Override public void visit(ArrayExpression expression) {} + @Override public void visit(BinaryOperatorExpression expression) {} + @Override public void visit(BooleanExpression expression) {} + @Override public void visit(CastExpression expression) {} + @Override public void visit(CommentExpression expression) {} + @Override public void visit(ConstructorInvocationExpression expression) {} + @Override public void visit(ConstructorReferenceExpression expression) {} + @Override public void visit(DoubleConstantExpression expression) {} + @Override public void visit(EnumConstantReferenceExpression expression) {} + @Override public void visit(Expressions expression) {} + @Override public void visit(FieldReferenceExpression expression) {} + @Override public void visit(FloatConstantExpression expression) {} + @Override public void visit(IntegerConstantExpression expression) {} + @Override public void visit(InstanceOfExpression expression) {} + @Override public void visit(LambdaFormalParametersExpression expression) {} + @Override public void visit(LambdaIdentifiersExpression expression) {} + @Override public void visit(LengthExpression expression) {} + @Override public void visit(LocalVariableReferenceExpression expression) {} + @Override public void visit(LongConstantExpression expression) {} + @Override public void visit(MethodInvocationExpression expression) {} + @Override public void visit(MethodReferenceExpression expression) {} + @Override public void visit(NewArray expression) {} + @Override public void visit(NewExpression expression) {} + @Override public void visit(NewInitializedArray expression) {} + @Override public void visit(NewInnerExpression expression) {} + @Override public void visit(NullExpression expression) {} + @Override public void visit(ObjectTypeReferenceExpression expression) {} + @Override public void visit(ParenthesesExpression expression) {} + @Override public void visit(PostOperatorExpression expression) {} + @Override public void visit(PreOperatorExpression expression) {} + @Override public void visit(StringConstantExpression expression) {} + @Override public void visit(SuperConstructorInvocationExpression expression) {} + @Override public void visit(SuperExpression expression) {} + @Override public void visit(TernaryOperatorExpression expression) {} + @Override public void visit(ThisExpression expression) {} + @Override public void visit(TypeReferenceDotClassExpression expression) {} +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java new file mode 100644 index 00000000..a5a9dd61 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class ArrayExpression extends AbstractLineNumberTypeExpression { + protected Expression expression; + protected Expression index; + + public ArrayExpression(Expression expression, Expression index) { + super(createItemType(expression)); + this.expression = expression; + this.index = index; + } + + public ArrayExpression(int lineNumber, Expression expression, Expression index) { + super(lineNumber, createItemType(expression)); + this.expression = expression; + this.index = index; + } + + public Expression getExpression() { + return expression; + } + + public Expression getIndex() { + return index; + } + + public void setIndex(Expression index) { + this.index = index; + } + + @Override + public int getPriority() { + return 1; + } + + protected static Type createItemType(Expression expression) { + Type type = expression.getType(); + int dimension = type.getDimension(); + + assert dimension > 0 : "createItemType : negative dimension"; + + return type.createType((dimension > 0) ? dimension-1 : 0); + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ArrayExpression{" + expression + "[" + index + "]}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java new file mode 100644 index 00000000..a6a6c89f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.util.Base; + +public interface BaseExpression extends Base { + void accept(ExpressionVisitor visitor); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java new file mode 100644 index 00000000..e01b3a5b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class BinaryOperatorExpression extends AbstractLineNumberTypeExpression { + protected Expression leftExpression; + protected String operator; + protected Expression rightExpression; + protected int priority; + + public BinaryOperatorExpression(int lineNumber, Type type, Expression leftExpression, String operator, Expression rightExpression, int priority) { + super(lineNumber, type); + this.operator = operator; + this.leftExpression = leftExpression; + this.rightExpression = rightExpression; + this.priority = priority; + } + + public Expression getLeftExpression() { + return leftExpression; + } + + public void setLeftExpression(Expression leftExpression) { + this.leftExpression = leftExpression; + } + + @SuppressWarnings("unchecked") + public T getGenericLeftExpression() { + return (T) leftExpression; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public Expression getRightExpression() { + return rightExpression; + } + + public void setRightExpression(Expression rightExpression) { + this.rightExpression = rightExpression; + } + + @SuppressWarnings("unchecked") + public T getGenericRightExpression() { + return (T) rightExpression; + } + + public int getPriority() { + return priority; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "BinaryOperatorExpression{" + leftExpression.toString() + ' ' + operator + ' ' + rightExpression.toString() + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java new file mode 100644 index 00000000..ad5812f4 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class BooleanExpression extends AbstractLineNumberExpression { + public static final BooleanExpression TRUE = new BooleanExpression(true); + public static final BooleanExpression FALSE = new BooleanExpression(false); + + protected boolean value; + + protected BooleanExpression(boolean value) { + this.value = value; + } + + public BooleanExpression(int lineNumber, boolean value) { + super(lineNumber); + this.value = value; + } + + @Override + public Type getType() { + return PrimitiveType.TYPE_BOOLEAN; + } + + public boolean isTrue() { + return value; + } + + public boolean isFalse() { + return !value; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "BooleanExpression{" + value + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java new file mode 100644 index 00000000..d00b6cc3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class CastExpression extends AbstractLineNumberTypeExpression { + protected Expression expression; + protected boolean explicit; + + public CastExpression(Type type, Expression expression) { + super(type); + this.expression = expression; + this.explicit = true; + } + + public CastExpression(int lineNumber, Type type, Expression expression) { + super(lineNumber, type); + this.expression = expression; + this.explicit = true; + } + + public CastExpression(int lineNumber, Type type, Expression expression, boolean explicit) { + super(lineNumber, type); + this.expression = expression; + this.explicit = explicit; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public boolean isExplicit() { + return explicit; + } + + @Override + public int getPriority() { + return 3; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "CastExpression{cast (" + type + ") " + expression + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/CommentExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CommentExpression.java new file mode 100644 index 00000000..f15c530c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CommentExpression.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class CommentExpression implements Expression { + protected String text; + + public CommentExpression(String text) { + this.text = text; + } + + @Override + public int getLineNumber() { + return UNKNOWN_LINE_NUMBER; + } + + @Override + public Type getType() { + return PrimitiveType.TYPE_VOID; + } + + public String getText() { + return text; + } + + @Override + public int getPriority() { + return 0; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "CommentExpression{" + text + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java new file mode 100644 index 00000000..46fb65e5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; + +public class ConstructorInvocationExpression extends ConstructorReferenceExpression { + protected BaseExpression parameters; + + public ConstructorInvocationExpression(ObjectType type, String descriptor, BaseExpression parameters) { + super(PrimitiveType.TYPE_VOID, type, descriptor); + this.parameters = parameters; + } + + public ConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, BaseExpression parameters) { + super(lineNumber, PrimitiveType.TYPE_VOID, type, descriptor); + this.parameters = parameters; + } + + public BaseExpression getParameters() { + return parameters; + } + + public void setParameters(BaseExpression parameters) { + this.parameters = parameters; + } + + @Override + public int getPriority() { + return 1; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ConstructorInvocationExpression{call this(" + descriptor + ")}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java new file mode 100644 index 00000000..8ef90fc4 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class ConstructorReferenceExpression extends AbstractLineNumberTypeExpression { + protected ObjectType objectType; + protected String descriptor; + + public ConstructorReferenceExpression(Type type, ObjectType objectType, String descriptor) { + super(type); + this.objectType = objectType; + this.descriptor = descriptor; + } + + public ConstructorReferenceExpression(int lineNumber, Type type, ObjectType objectType, String descriptor) { + super(lineNumber, type); + this.objectType = objectType; + this.descriptor = descriptor; + } + + public ObjectType getObjectType() { + return objectType; + } + + public String getDescriptor() { + return descriptor; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java new file mode 100644 index 00000000..aaa23b7e --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; + +public class DoubleConstantExpression extends AbstractLineNumberTypeExpression { + protected double value; + + public DoubleConstantExpression(double value) { + super(PrimitiveType.TYPE_DOUBLE); + this.value = value; + } + + public DoubleConstantExpression(int lineNumber, double value) { + super(lineNumber, PrimitiveType.TYPE_DOUBLE); + this.value = value; + } + + public double getValue() { + return value; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "DoubleConstantExpression{" + value + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java new file mode 100644 index 00000000..458c1d63 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class EnumConstantReferenceExpression extends AbstractLineNumberExpression { + protected ObjectType type; + protected String name; + + public EnumConstantReferenceExpression(ObjectType type, String name) { + this.type = type; + this.name = name; + } + + public EnumConstantReferenceExpression(int lineNumber, ObjectType type, String name) { + super(lineNumber); + this.type = type; + this.name = name; + } + + @Override + public Type getType() { + return type; + } + + public ObjectType getObjectType() { + return type; + } + + public String getName() { + return name; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "EnumConstantReferenceExpression{lastType=" + type + ", name=" + name + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java new file mode 100644 index 00000000..0fe14207 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.model.javasyntax.type.Type; + +/* Priority Operator Operation Order of Evaluation + * 1 [ ] Array index Left to Right + * () Method call + * . Member access + * ++ Postfix increment + * -- Postfix decrement + * 2 ++ Prefix increment Right to Left + * -- Prefix decrement + * + - Unary plus, minus + * ~ Bitwise NOT + * ! Boolean (logical) NOT + * 3 (type) Type cast Right to Left + * new Object creation + * 4 + String concatenation Left to Right + * 5 * / % Multiplication, division, remainder Left to Right + * 6 + - Addition, subtraction Left to Right + * 7 << Signed bit shift left to right Left to Right + * >> Signed bit shift right to left + * >>> Unsigned bit shift right to left + * 8 < <= Less than, less than or equal to Left to Right + * > >= Greater than, greater than or equal to + * instanceof Reference test + * 9 == Equal to Left to Right + * != Not equal to + * 10 & Bitwise AND Left to Right + * & Boolean (logical) AND + * 11 ^ Bitwise XOR Left to Right + * ^ Boolean (logical) XOR + * 12 | Bitwise OR Left to Right + * | Boolean (logical) OR + * 13 && Boolean (logical) AND Left to Right + * 14 || Boolean (logical) OR Left to Right + * 15 ? : Conditional Right to Left + * 16 = Assignment Right to Left + * *= /= += Combinated assignment + * -= %= (operation and assignment) + * <<= >>= + * >>>= + * &= ^= |= + * 17 -> Lambda Right to Left + * + * References: + * - http://introcs.cs.princeton.edu/java/11precedence + * - The Java® Language Specification Java SE 8 Edition, 15.2 Forms of Expressions + */ +public interface Expression extends BaseExpression { + int UNKNOWN_LINE_NUMBER = Printer.UNKNOWN_LINE_NUMBER; + + int getLineNumber(); + + Type getType(); + + int getPriority(); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java new file mode 100644 index 00000000..af4ec550 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +public interface ExpressionVisitor { + void visit(ArrayExpression expression); + void visit(BinaryOperatorExpression expression); + void visit(BooleanExpression expression); + void visit(CastExpression expression); + void visit(CommentExpression expression); + void visit(ConstructorInvocationExpression expression); + void visit(ConstructorReferenceExpression expression); + void visit(DoubleConstantExpression expression); + void visit(EnumConstantReferenceExpression expression); + void visit(Expressions expression); + void visit(FieldReferenceExpression expression); + void visit(FloatConstantExpression expression); + void visit(IntegerConstantExpression expression); + void visit(InstanceOfExpression expression); + void visit(LambdaFormalParametersExpression expression); + void visit(LambdaIdentifiersExpression expression); + void visit(LengthExpression expression); + void visit(LocalVariableReferenceExpression expression); + void visit(LongConstantExpression expression); + void visit(MethodInvocationExpression expression); + void visit(MethodReferenceExpression expression); + void visit(NewArray expression); + void visit(NewExpression expression); + void visit(NewInitializedArray expression); + void visit(NewInnerExpression expression); + void visit(NullExpression expression); + void visit(ObjectTypeReferenceExpression expression); + void visit(ParenthesesExpression expression); + void visit(PostOperatorExpression expression); + void visit(PreOperatorExpression expression); + void visit(StringConstantExpression expression); + void visit(SuperConstructorInvocationExpression expression); + void visit(SuperExpression expression); + void visit(TernaryOperatorExpression expression); + void visit(ThisExpression expression); + void visit(TypeReferenceDotClassExpression expression); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java new file mode 100644 index 00000000..7f3f6c58 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class Expressions extends DefaultList implements BaseExpression { + + public Expressions() {} + + public Expressions(int capacity) { + super(capacity); + } + + public Expressions(Collection collection) { + super(collection); + assert (collection != null) && (collection.size() > 1) : "Uses 'Expression' or sub class instead"; + } + + @SuppressWarnings("unchecked") + public Expressions(E expression, E... expressions) { + super(expression, expressions); + assert (expressions != null) && (expressions.length > 0) : "Uses 'Expression' or sub class instead"; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java new file mode 100644 index 00000000..c48f65c8 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class FieldReferenceExpression extends AbstractLineNumberTypeExpression { + protected Expression expression; + protected String internalTypeName; + protected String name; + protected String descriptor; + + public FieldReferenceExpression(Type type, Expression expression, String internalTypeName, String name, String descriptor) { + super(type); + this.expression = expression; + this.internalTypeName = internalTypeName; + this.name = name; + this.descriptor = descriptor; + } + + public FieldReferenceExpression(int lineNumber, Type type, Expression expression, String internalTypeName, String name, String descriptor) { + super(lineNumber, type); + this.expression = expression; + this.internalTypeName = internalTypeName; + this.name = name; + this.descriptor = descriptor; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public String getInternalTypeName() { + return internalTypeName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescriptor() { + return descriptor; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "FieldReferenceExpression{lastType=" + type + ", expression=" + expression + ", name=" + name + ", descriptor=" + descriptor + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java new file mode 100644 index 00000000..a0203933 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; + +public class FloatConstantExpression extends AbstractLineNumberTypeExpression { + protected float value; + + public FloatConstantExpression(float value) { + super(PrimitiveType.TYPE_FLOAT); + this.value = value; + } + + public FloatConstantExpression(int lineNumber, float value) { + super(lineNumber, PrimitiveType.TYPE_FLOAT); + this.value = value; + } + + public float getValue() { + return value; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "FloatConstantExpression{" + value + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java new file mode 100644 index 00000000..1c9333c9 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class InstanceOfExpression extends AbstractLineNumberExpression { + protected Expression expression; + protected Type instanceOfType; + + public InstanceOfExpression(Expression expression, ObjectType instanceOfType) { + this.expression = expression; + this.instanceOfType = instanceOfType; + } + + public InstanceOfExpression(int lineNumber, Expression expression, Type instanceOfType) { + super(lineNumber); + this.expression = expression; + this.instanceOfType = instanceOfType; + } + + public Expression getExpression() { + return expression; + } + + public Type getInstanceOfType() { + return instanceOfType; + } + + @Override + public Type getType() { + return PrimitiveType.TYPE_BOOLEAN; + } + + @Override + public int getPriority() { + return 8; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java new file mode 100644 index 00000000..74aec084 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; + +import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; + + +public class IntegerConstantExpression extends AbstractLineNumberTypeExpression { + protected int value; + + public IntegerConstantExpression(Type type, int value) { + super(type); + this.value = value; + assert type.isPrimitive(); + } + + public IntegerConstantExpression(int lineNumber, Type type, int value) { + super(lineNumber, type); + this.value = value; + assert type.isPrimitive(); + } + + public int getValue() { + return value; + } + + @Override + public void setType(Type type) { + assert type.isPrimitive() && checkType(type) : "setType : incompatible types"; + super.setType(type); + } + + protected boolean checkType(Type type) { + if (type.isPrimitive()) { + switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(((PrimitiveType)type).getFlags())) { + case FLAG_BYTE: + return (Byte.MIN_VALUE <= value) && (value <= Byte.MAX_VALUE); + case FLAG_CHAR: + return (Character.MIN_VALUE <= (char)value) && ((char)value <= Character.MAX_VALUE); + case FLAG_SHORT: + return (Short.MIN_VALUE <= value) && (value <= Short.MAX_VALUE); + case FLAG_BOOLEAN: + return (0 <= value) && (value <= 1); + default: + return (Integer.MIN_VALUE <= value) && (value <= Integer.MAX_VALUE); + } + } + + return false; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "IntegerConstantExpression{type=" + type + ", value=" + value + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java new file mode 100644 index 00000000..bf0e68f5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.declaration.BaseFormalParameter; +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class LambdaFormalParametersExpression extends AbstractLambdaExpression { + protected BaseFormalParameter parameters; + + public LambdaFormalParametersExpression(Type type, BaseFormalParameter parameters, BaseStatement statements) { + super(type, statements); + this.parameters = parameters; + } + + public LambdaFormalParametersExpression(int lineNumber, Type type, BaseFormalParameter parameters, BaseStatement statements) { + super(lineNumber, type, statements); + this.parameters = parameters; + } + + public BaseFormalParameter getParameters() { + return parameters; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LambdaFormalParametersExpression{" + parameters + " -> " + statements + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java new file mode 100644 index 00000000..49673a66 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; +import org.jd.core.v1.model.javasyntax.type.Type; + +import java.util.List; + +public class LambdaIdentifiersExpression extends AbstractLambdaExpression { + protected Type returnedType; + protected List parameters; + + public LambdaIdentifiersExpression(Type type, Type returnedType, List parameters, BaseStatement statements) { + super(type, statements); + this.returnedType = returnedType; + this.parameters = parameters; + } + + public LambdaIdentifiersExpression(int lineNumber, Type type, Type returnedType, List parameters, BaseStatement statements) { + super(lineNumber, type, statements); + this.returnedType = returnedType; + this.parameters = parameters; + } + + public Type getReturnedType() { + return returnedType; + } + + public List getParameters() { + return parameters; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LambdaIdentifiersExpression{" + parameters + " -> " + statements + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java new file mode 100644 index 00000000..122d89a9 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class LengthExpression extends AbstractLineNumberExpression { + protected Expression expression; + + public LengthExpression(Expression expression) { + this.expression = expression; + } + + public LengthExpression(int lineNumber, Expression expression) { + super(lineNumber); + this.expression = expression; + } + + @Override + public Type getType() { + return PrimitiveType.TYPE_INT; + } + + public Expression getExpression() { + return expression; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LengthExpression{" + expression + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java new file mode 100644 index 00000000..34db3bb6 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class LocalVariableReferenceExpression extends AbstractLineNumberTypeExpression { + protected String name; + + public LocalVariableReferenceExpression(Type type, String name) { + super(type); + this.name = name; + } + + public LocalVariableReferenceExpression(int lineNumber, Type type, String name) { + super(lineNumber, type); + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LocalVariableReferenceExpression{lastType=" + type + ", name=" + name + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java new file mode 100644 index 00000000..fbdd8578 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; + +public class LongConstantExpression extends AbstractLineNumberTypeExpression { + protected long value; + + public LongConstantExpression(long value) { + super(PrimitiveType.TYPE_LONG); + this.value = value; + } + + public LongConstantExpression(int lineNumber, long value) { + super(lineNumber, PrimitiveType.TYPE_LONG); + this.value = value; + } + + public long getValue() { + return value; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LongConstantExpression{" + value + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java new file mode 100644 index 00000000..adb37e85 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class MethodInvocationExpression extends MethodReferenceExpression { + protected BaseExpression parameters; + + public MethodInvocationExpression(Type type, Expression expression, String internalTypeName, String name, String descriptor) { + super(type, expression, internalTypeName, name, descriptor); + } + + public MethodInvocationExpression(int lineNumber, Type type, Expression expression, String internalTypeName, String name, String descriptor) { + super(lineNumber, type, expression, internalTypeName, name, descriptor); + } + + public MethodInvocationExpression(Type type, Expression expression, String internalTypeName, String name, String descriptor, BaseExpression parameters) { + super(type, expression, internalTypeName, name, descriptor); + this.parameters = parameters; + } + + public MethodInvocationExpression(int lineNumber, Type type, Expression expression, String internalTypeName, String name, String descriptor, BaseExpression parameters) { + super(lineNumber, type, expression, internalTypeName, name, descriptor); + this.parameters = parameters; + } + + public BaseExpression getParameters() { + return parameters; + } + + public void setParameters(BaseExpression parameters) { + this.parameters = parameters; + } + + @Override + public int getPriority() { + return 1; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "MethodInvocationExpression{call " + expression + " . " + name + "(" + descriptor + ")}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java new file mode 100644 index 00000000..ee512aee --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class MethodReferenceExpression extends AbstractLineNumberTypeExpression { + protected Expression expression; + protected String internalTypeName; + protected String name; + protected String descriptor; + + public MethodReferenceExpression(Type type, Expression expression, String internalTypeName, String name, String descriptor) { + super(type); + this.expression = expression; + this.internalTypeName = internalTypeName; + this.name = name; + this.descriptor = descriptor; + } + + public MethodReferenceExpression(int lineNumber, Type type, Expression expression, String internalTypeName, String name, String descriptor) { + super(lineNumber, type); + this.expression = expression; + this.internalTypeName = internalTypeName; + this.name = name; + this.descriptor = descriptor; + } + + public Expression getExpression() { + return expression; + } + + public String getInternalTypeName() { + return internalTypeName; + } + + public String getName() { + return name; + } + + public String getDescriptor() { + return descriptor; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java new file mode 100644 index 00000000..948f01ba --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class NewArray extends AbstractLineNumberTypeExpression { + protected BaseExpression dimensionExpressionList; + + public NewArray(int lineNumber, Type type, BaseExpression dimensionExpressionList) { + super(lineNumber, type); + this.dimensionExpressionList = dimensionExpressionList; + } + + public BaseExpression getDimensionExpressionList() { + return dimensionExpressionList; + } + + @Override + public int getPriority() { + return 3; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "NewArray{" + type + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java new file mode 100644 index 00000000..4f0e558b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; +import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class NewExpression extends AbstractLineNumberExpression { + protected BaseTypeArgument nonWildcardTypeArguments; + protected ObjectType type; + protected BaseExpression parameters; + protected BodyDeclaration bodyDeclaration; + + public NewExpression(int lineNumber, ObjectType type) { + super(lineNumber); + this.type = type; + } + + public NewExpression(int lineNumber, ObjectType type, BodyDeclaration bodyDeclaration) { + super(lineNumber); + this.type = type; + this.bodyDeclaration = bodyDeclaration; + } + + public NewExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, BaseExpression parameters, BodyDeclaration bodyDeclaration) { + super(lineNumber); + this.nonWildcardTypeArguments = nonWildcardTypeArguments; + this.type = type; + this.parameters = parameters; + this.bodyDeclaration = bodyDeclaration; + } + + public BaseTypeArgument getNonWildcardTypeArguments() { + return nonWildcardTypeArguments; + } + + public ObjectType getObjectType() { + return type; + } + + public void setObjectType(ObjectType type) { + this.type = type; + } + + @Override + public Type getType() { + return type; + } + + @Override + public int getPriority() { + return 3; + } + + public BaseExpression getParameters() { + return parameters; + } + + public void setParameters(BaseExpression parameters) { + this.parameters = parameters; + } + + public BodyDeclaration getBodyDeclaration() { + return bodyDeclaration; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java new file mode 100644 index 00000000..cfd831b6 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.declaration.ArrayVariableInitializer; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class NewInitializedArray extends AbstractLineNumberTypeExpression { + protected ArrayVariableInitializer arrayInitializer; + + public NewInitializedArray(Type type, ArrayVariableInitializer arrayInitializer) { + super(type); + this.arrayInitializer = arrayInitializer; + } + + public NewInitializedArray(int lineNumber, Type type, ArrayVariableInitializer arrayInitializer) { + super(lineNumber, type); + this.arrayInitializer = arrayInitializer; + } + + public ArrayVariableInitializer getArrayInitializer() { + return arrayInitializer; + } + + @Override + public int getPriority() { + return 3; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java new file mode 100644 index 00000000..cc65bff8 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; +import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; +import org.jd.core.v1.model.javasyntax.type.ObjectType; + +public class NewInnerExpression extends NewExpression { + protected Expression expression; + + public NewInnerExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, BaseExpression parameters, BodyDeclaration bodyDeclaration, Expression expression) { + super(lineNumber, nonWildcardTypeArguments, type, parameters, bodyDeclaration); + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + @Override + public int getPriority() { + return 3; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java new file mode 100644 index 00000000..4c818bd6 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class NullExpression extends AbstractLineNumberTypeExpression { + public NullExpression(Type type) { + super(type); + } + + public NullExpression(int lineNumber, Type type) { + super(lineNumber, type); + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "NullExpression{type=" + type + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java new file mode 100644 index 00000000..09abe476 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class ObjectTypeReferenceExpression implements Expression { + protected int lineNumber; + protected ObjectType type; + protected boolean explicit; + + public ObjectTypeReferenceExpression(ObjectType type) { + this.type = type; + this.explicit = true; + } + + public ObjectTypeReferenceExpression(int lineNumber, ObjectType type) { + this.lineNumber = lineNumber; + this.type = type; + this.explicit = true; + } + + public ObjectTypeReferenceExpression(ObjectType type, boolean explicit) { + this.type = type; + this.explicit = explicit; + } + + public ObjectTypeReferenceExpression(int lineNumber, ObjectType type, boolean explicit) { + this.lineNumber = lineNumber; + this.type = type; + this.explicit = explicit; + } + + @Override + public int getLineNumber() { + return lineNumber; + } + + public ObjectType getObjectType() { + return type; + } + + @Override + public Type getType() { + return type; + } + + public boolean isExplicit() { + return explicit; + } + + @Override + public int getPriority() { + return 0; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ObjectTypeReferenceExpression{" + type + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java new file mode 100644 index 00000000..0724b7d3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class ParenthesesExpression extends AbstractLineNumberExpression { + protected Expression expression; + + public ParenthesesExpression(Expression expression) { + super(expression.getLineNumber()); + this.expression = expression; + } + + @Override + public Type getType() { + return expression.getType(); + } + + public Expression getExpression() { + return expression; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java new file mode 100644 index 00000000..2c2a0dcd --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class PostOperatorExpression extends AbstractLineNumberExpression { + protected String operator; + protected Expression expression; + + public PostOperatorExpression(Expression expression, String operator) { + this.operator = operator; + this.expression = expression; + } + + public PostOperatorExpression(int lineNumber, Expression expression, String operator) { + super(lineNumber); + this.operator = operator; + this.expression = expression; + } + + public String getOperator() { + return operator; + } + + public Expression getExpression() { + return expression; + } + + @Override + public Type getType() { + return expression.getType(); + } + + @Override + public int getPriority() { + return 1; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "PostOperatorExpression{" + expression + " " + operator + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java new file mode 100644 index 00000000..1c3d7fb0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class PreOperatorExpression extends AbstractLineNumberExpression { + protected String operator; + protected Expression expression; + + public PreOperatorExpression(String operator, Expression expression) { + this.operator = operator; + this.expression = expression; + } + + public PreOperatorExpression(int lineNumber, String operator, Expression expression) { + super(lineNumber); + this.operator = operator; + this.expression = expression; + } + + public String getOperator() { + return operator; + } + + public Expression getExpression() { + return expression; + } + + @Override + public Type getType() { + return expression.getType(); + } + + @Override + public int getPriority() { + return 2; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "PreOperatorExpression{" + operator + " " + expression + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java new file mode 100644 index 00000000..c8b6fead --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class StringConstantExpression extends AbstractLineNumberExpression { + protected String string; + + public StringConstantExpression(String string) { + this.string = string; + } + + public StringConstantExpression(int lineNumber, String string) { + super(lineNumber); + this.string = string; + } + + public String getString() { + return string; + } + + @Override + public Type getType() { + return ObjectType.TYPE_STRING; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "StringConstantExpression{\"" + string + "\"}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java new file mode 100644 index 00000000..acca3bde --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; + +public class SuperConstructorInvocationExpression extends ConstructorReferenceExpression { + protected BaseExpression parameters; + + public SuperConstructorInvocationExpression(ObjectType type, String descriptor, BaseExpression parameters) { + super(PrimitiveType.TYPE_VOID, type, descriptor); + this.parameters = parameters; + } + + public SuperConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, BaseExpression parameters) { + super(lineNumber, PrimitiveType.TYPE_VOID, type, descriptor); + this.parameters = parameters; + } + + public BaseExpression getParameters() { + return parameters; + } + + public void setParameters(BaseExpression parameters) { + this.parameters = parameters; + } + + @Override + public int getPriority() { + return 1; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "SuperConstructorInvocationExpression{call super(" + descriptor + ")}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java new file mode 100644 index 00000000..c42a9371 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class SuperExpression extends AbstractLineNumberExpression { + protected ObjectType type; + + public SuperExpression(ObjectType type) { + this.type = type; + } + + public SuperExpression(int lineNumber, ObjectType type) { + super(lineNumber); + this.type = type; + } + + public ObjectType getObjectType() { + return type; + } + + @Override + public Type getType() { + return type; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "SuperExpression{" + type + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java new file mode 100644 index 00000000..9ff999fe --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.Type; + +public class TernaryOperatorExpression extends AbstractLineNumberTypeExpression { + protected Expression condition; + protected Expression expressionTrue; + protected Expression expressionFalse; + + public TernaryOperatorExpression(Expression condition, Expression expressionTrue, Expression expressionFalse) { + super(getType(expressionTrue, expressionFalse)); + this.condition = condition; + this.expressionTrue = expressionTrue; + this.expressionFalse = expressionFalse; + } + + public TernaryOperatorExpression(Type type, Expression condition, Expression expressionTrue, Expression expressionFalse) { + super(type); + this.condition = condition; + this.expressionTrue = expressionTrue; + this.expressionFalse = expressionFalse; + } + + public TernaryOperatorExpression(int lineNumber, Expression condition, Expression expressionTrue, Expression expressionFalse) { + super(lineNumber, getType(expressionTrue, expressionFalse)); + this.condition = condition; + this.expressionTrue = expressionTrue; + this.expressionFalse = expressionFalse; + } + + public TernaryOperatorExpression(int lineNumber, Type type, Expression condition, Expression expressionTrue, Expression expressionFalse) { + super(lineNumber, type); + this.condition = condition; + this.expressionTrue = expressionTrue; + this.expressionFalse = expressionFalse; + } + + public Expression getCondition() { + return condition; + } + + public void setCondition(Expression condition) { + this.condition = condition; + } + + public Expression getExpressionTrue() { + return expressionTrue; + } + + public void setExpressionTrue(Expression expressionTrue) { + this.expressionTrue = expressionTrue; + } + + public Expression getExpressionFalse() { + return expressionFalse; + } + + public void setExpressionFalse(Expression expressionFalse) { + this.expressionFalse = expressionFalse; + } + + @Override + public int getPriority() { + return 15; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "TernaryOperatorExpression{" + condition + " ? " + expressionTrue + " : " + expressionFalse + "}"; + } + + protected static Type getType(Expression expressionTrue, Expression expressionFalse) { + if (expressionTrue instanceof NullExpression) { + return expressionFalse.getType(); + } else { + return expressionTrue.getType(); + } + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java new file mode 100644 index 00000000..c8b92af5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class ThisExpression extends AbstractLineNumberExpression { + protected ObjectType type; + protected boolean explicit; + + public ThisExpression(ObjectType type) { + this.type = type; + this.explicit = true; + } + + public ThisExpression(int lineNumber, ObjectType type) { + super(lineNumber); + this.type = type; + this.explicit = true; + } + + public ObjectType getObjectType() { + return type; + } + + @Override + public Type getType() { + return type; + } + + public boolean isExplicit() { + return explicit; + } + + public void setExplicit(boolean explicit) { + this.explicit = explicit; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ThisExpression{" + type + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java new file mode 100644 index 00000000..2500b76c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class TypeReferenceDotClassExpression implements Expression { + protected int lineNumber; + protected Type typeDotClass; + + public TypeReferenceDotClassExpression(Type typeDotClass) { + this.typeDotClass = typeDotClass; + } + + public TypeReferenceDotClassExpression(int lineNumber, Type typeDotClass) { + this.lineNumber = lineNumber; + this.typeDotClass = typeDotClass; + } + + @Override + public int getLineNumber() { + return lineNumber; + } + + public Type getTypeDotClass() { + return typeDotClass; + } + + @Override + public Type getType() { + return ObjectType.TYPE_CLASS; + } + + @Override + public int getPriority() { + return 0; + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "TypeReferenceDotClassExpression{" + typeDotClass + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/AbstractNopReferenceVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AbstractNopReferenceVisitor.java new file mode 100644 index 00000000..83bf1783 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AbstractNopReferenceVisitor.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public abstract class AbstractNopReferenceVisitor implements ReferenceVisitor { + @Override public void visit(AnnotationReference reference) {} + @Override public void visit(AnnotationReferences references) {} + @Override public void visit(ElementValues references) {} + @Override public void visit(ElementValuePair reference) {} + @Override public void visit(ElementValuePairs references) {} + @Override public void visit(InnerObjectReference reference) {} + @Override public void visit(ObjectReference reference) {} +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationElementValue.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationElementValue.java new file mode 100644 index 00000000..80496d2c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationElementValue.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public class AnnotationElementValue extends AnnotationReference implements ElementValue { + + public AnnotationElementValue(AnnotationReference annotationReference) { + super(annotationReference.getType(), + annotationReference.getElementValue(), + annotationReference.getElementValuePairs()); + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "AnnotationElementValue{type=" + type + ", elementValue=" + elementValue + ", elementValuePairs=" + elementValuePairs + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java new file mode 100644 index 00000000..60c0ccc7 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.model.javasyntax.type.ObjectType; + +public class AnnotationReference implements BaseAnnotationReference { + protected ObjectType type; + protected ElementValue elementValue; + protected BaseElementValuePair elementValuePairs; + + public AnnotationReference(ObjectType type) { + this.type = type; + } + + public AnnotationReference(ObjectType type, ElementValue elementValue) { + this.type = type; + this.elementValue = elementValue; + } + + public AnnotationReference(ObjectType type, BaseElementValuePair elementValuePairs) { + this.type = type; + this.elementValuePairs = elementValuePairs; + } + + protected AnnotationReference(ObjectType type, ElementValue elementValue, BaseElementValuePair elementValuePairs) { + this.type = type; + this.elementValue = elementValue; + this.elementValuePairs = elementValuePairs; + } + + public ObjectType getType() { + return type; + } + + public ElementValue getElementValue() { + return elementValue; + } + + public BaseElementValuePair getElementValuePairs() { + return elementValuePairs; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AnnotationReference)) return false; + + AnnotationReference that = (AnnotationReference) o; + + if (elementValue != null ? !elementValue.equals(that.elementValue) : that.elementValue != null) return false; + if (elementValuePairs != null ? !elementValuePairs.equals(that.elementValuePairs) : that.elementValuePairs != null) + return false; + if (!type.equals(that.type)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = type.hashCode(); + result = 31 * result + (elementValue != null ? elementValue.hashCode() : 0); + result = 31 * result + (elementValuePairs != null ? elementValuePairs.hashCode() : 0); + return result; + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReferences.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReferences.java new file mode 100644 index 00000000..59c3ff62 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReferences.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class AnnotationReferences extends DefaultList implements BaseAnnotationReference { + public AnnotationReferences() { + } + + public AnnotationReferences(int capacity) { + super(capacity); + } + + public AnnotationReferences(Collection collection) { + super(collection); + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseAnnotationReference.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseAnnotationReference.java new file mode 100644 index 00000000..567b1de2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseAnnotationReference.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public interface BaseAnnotationReference extends Reference {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValue.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValue.java new file mode 100644 index 00000000..8f758b9c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValue.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.util.Base; + +public interface BaseElementValue extends Reference, Base {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValuePair.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValuePair.java new file mode 100644 index 00000000..a4248019 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/BaseElementValuePair.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.util.Base; + +public interface BaseElementValuePair extends Reference, Base {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValue.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValue.java new file mode 100644 index 00000000..1bec1c1b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValue.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public interface ElementValue extends BaseElementValue { + public static final byte EV_UNKNOWN= 0; + public static final byte EV_PRIMITIVE_TYPE= 1; + public static final byte EV_ENUM_CONST_VALUE= 2; + public static final byte EV_CLASS_INFO= 3; + public static final byte EV_ANNOTATION_VALUE= 4; + public static final byte EV_ARRAY_VALUE= 5; +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValueArrayInitializerElementValue.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValueArrayInitializerElementValue.java new file mode 100644 index 00000000..4a4974e7 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValueArrayInitializerElementValue.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public class ElementValueArrayInitializerElementValue implements ElementValue { + protected BaseElementValue elementValueArrayInitializer; + + public ElementValueArrayInitializerElementValue() { + this.elementValueArrayInitializer = null; + } + + public ElementValueArrayInitializerElementValue(BaseElementValue elementValueArrayInitializer) { + this.elementValueArrayInitializer = elementValueArrayInitializer; + } + + public BaseElementValue getElementValueArrayInitializer() { + return elementValueArrayInitializer; + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ElementValueArrayInitializerElementValue{" + elementValueArrayInitializer + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePair.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePair.java new file mode 100644 index 00000000..18989532 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePair.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public class ElementValuePair implements BaseElementValuePair { + protected String name; + protected ElementValue elementValue; + + public ElementValuePair(String name, ElementValue elementValue) { + this.name = name; + this.elementValue = elementValue; + } + + public String getName() { + return name; + } + + public ElementValue getElementValue() { + return elementValue; + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ElementValuePair{name=" + name + ", elementValue=" + elementValue + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java new file mode 100644 index 00000000..9507d48a --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class ElementValuePairs extends DefaultList implements BaseElementValuePair { + public ElementValuePairs() { + } + + public ElementValuePairs(int capacity) { + super(capacity); + } + + public ElementValuePairs(Collection collection) { + super(collection); + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ElementValuePairs{" + super.toString() + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java new file mode 100644 index 00000000..754e09c5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.util.DefaultList; + +import java.util.Collection; + +public class ElementValues extends DefaultList implements BaseElementValue { + public ElementValues() { + } + + public ElementValues(int capacity) { + super(capacity); + } + + public ElementValues(Collection collection) { + super(collection); + assert (collection != null) && (collection.size() > 1) : "Uses 'ElementValue' or sub class instead"; + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ElementValues{" + super.toString() + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java new file mode 100644 index 00000000..a0463726 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class ExpressionElementValue implements ElementValue { + protected Expression expression; + + public ExpressionElementValue(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ExpressionElementValue{" + expression + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/InnerObjectReference.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/InnerObjectReference.java new file mode 100644 index 00000000..5fc46f63 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/InnerObjectReference.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; +import org.jd.core.v1.model.javasyntax.type.InnerObjectType; +import org.jd.core.v1.model.javasyntax.type.ObjectType; + +public class InnerObjectReference extends InnerObjectType implements Reference { + + public InnerObjectReference(String internalName, String qualifiedName, String name, ObjectType outerType) { + super(internalName, qualifiedName, name, outerType); + } + + public InnerObjectReference(String internalName, String qualifiedName, String name, int dimension, ObjectType outerType) { + super(internalName, qualifiedName, name, dimension, outerType); + } + + public InnerObjectReference(String internalName, String qualifiedName, String name, BaseTypeArgument typeArguments, ObjectType outerType) { + super(internalName, qualifiedName, name, typeArguments, outerType); + } + + public InnerObjectReference(String internalName, String qualifiedName, String name, BaseTypeArgument typeArguments, int dimension, ObjectType outerType) { + super(internalName, qualifiedName, name, typeArguments, dimension, outerType); + } + + public InnerObjectReference(InnerObjectType iot) { + super(iot); + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ObjectReference.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ObjectReference.java new file mode 100644 index 00000000..29c8a5b8 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ObjectReference.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; +import org.jd.core.v1.model.javasyntax.type.ObjectType; + +public class ObjectReference extends ObjectType implements Reference { + public ObjectReference(String internalName, String qualifiedName, String name) { + super(internalName, qualifiedName, name); + } + + public ObjectReference(String internalName, String qualifiedName, String name, int dimension) { + super(internalName, qualifiedName, name, dimension); + } + + public ObjectReference(String internalName, String qualifiedName, String name, BaseTypeArgument typeArguments) { + super(internalName, qualifiedName, name, typeArguments); + } + + public ObjectReference(String internalName, String qualifiedName, String name, BaseTypeArgument typeArguments, int dimension) { + super(internalName, qualifiedName, name, typeArguments, dimension); + } + + @Override + public void accept(ReferenceVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/Reference.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/Reference.java new file mode 100644 index 00000000..2f398dfc --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/Reference.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public interface Reference { + void accept(ReferenceVisitor visitor); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ReferenceVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ReferenceVisitor.java new file mode 100644 index 00000000..4f05ae14 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ReferenceVisitor.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.reference; + +public interface ReferenceVisitor { + void visit(AnnotationElementValue reference); + void visit(AnnotationReference reference); + void visit(AnnotationReferences references); + void visit(ElementValueArrayInitializerElementValue reference); + void visit(ElementValues references); + void visit(ElementValuePair reference); + void visit(ElementValuePairs references); + void visit(ExpressionElementValue reference); + void visit(InnerObjectReference reference); + void visit(ObjectReference reference); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java new file mode 100644 index 00000000..8a467142 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public abstract class AbstractNopStatementVisitor implements StatementVisitor { + @Override public void visit(AssertStatement statement) {} + @Override public void visit(BreakStatement statement) {} + @Override public void visit(ByteCodeStatement statement) {} + @Override public void visit(CommentStatement statement) {} + @Override public void visit(ContinueStatement statement) {} + @Override public void visit(DoWhileStatement statement) {} + @Override public void visit(ExpressionStatement statement) {} + @Override public void visit(ForEachStatement statement) {} + @Override public void visit(ForStatement statement) {} + @Override public void visit(IfStatement statement) {} + @Override public void visit(IfElseStatement statement) {} + @Override public void visit(LabelStatement statement) {} + @Override public void visit(LambdaExpressionStatement statement) {} + @Override public void visit(LocalVariableDeclarationStatement statement) {} + @Override public void visit(ReturnExpressionStatement statement) {} + @Override public void visit(ReturnStatement statement) {} + @Override public void visit(Statements statement) {} + @Override public void visit(SwitchStatement statement) {} + @Override public void visit(SwitchStatement.DefaultLabel statement) {} + @Override public void visit(SwitchStatement.ExpressionLabel statement) {} + @Override public void visit(SwitchStatement.LabelBlock statement) {} + @Override public void visit(SwitchStatement.MultiLabelsBlock statement) {} + @Override public void visit(SynchronizedStatement statement) {} + @Override public void visit(ThrowStatement statement) {} + @Override public void visit(TryStatement statement) {} + @Override public void visit(TryStatement.CatchClause statement) {} + @Override public void visit(TryStatement.Resource statement) {} + @Override public void visit(TypeDeclarationStatement statement) {} + @Override public void visit(WhileStatement statement) {} +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java new file mode 100644 index 00000000..825988fa --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class AssertStatement implements Statement { + protected Expression condition; + protected Expression message; + + public AssertStatement(Expression condition, Expression message) { + this.condition = condition; + this.message = message; + } + + public Expression getCondition() { + return condition; + } + + public void setCondition(Expression condition) { + this.condition = condition; + } + + public Expression getMessage() { + return message; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java new file mode 100644 index 00000000..2e0071a8 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.util.Base; + +public interface BaseStatement extends Base { + void accept(StatementVisitor visitor); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java new file mode 100644 index 00000000..64b1a0ac --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public class BreakStatement implements Statement { + public static final BreakStatement BREAK = new BreakStatement(); + + protected String label; + + protected BreakStatement() { + this.label = null; + } + + public BreakStatement(String label) { + assert label != null; + + this.label = label; + } + + public String getLabel() { + return label; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ByteCodeStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ByteCodeStatement.java new file mode 100644 index 00000000..afb825bc --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ByteCodeStatement.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + + +public class ByteCodeStatement implements Statement { + protected String text; + + public ByteCodeStatement(String text) { + this.text = text; + } + + public String getText() { + return text; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/CommentStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/CommentStatement.java new file mode 100644 index 00000000..7e08f205 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/CommentStatement.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public class CommentStatement implements Statement { + protected String text; + + public CommentStatement(String text) { + this.text = text; + } + + public String getText() { + return text; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java new file mode 100644 index 00000000..b681ef15 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public class ContinueStatement implements Statement { + public static final ContinueStatement CONTINUE = new ContinueStatement(); + + protected String label; + + protected ContinueStatement() { + this.label = null; + } + + public ContinueStatement(String label) { + assert label != null; + + this.label = label; + } + + public String getLabel() { + return label; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java new file mode 100644 index 00000000..e47ec033 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class DoWhileStatement implements Statement { + protected Expression condition; + protected BaseStatement statements; + + public DoWhileStatement(Expression condition, BaseStatement statements) { + this.condition = condition; + this.statements = statements; + } + + public Expression getCondition() { + return condition; + } + + public void setCondition(Expression condition) { + this.condition = condition; + } + + public BaseStatement getStatements() { + return statements; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java new file mode 100644 index 00000000..8e55dcd0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class ExpressionStatement implements Statement { + protected Expression expression; + + public ExpressionStatement(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ExpressionStatement{" + expression.toString() + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java new file mode 100644 index 00000000..dc34de90 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class ForEachStatement implements Statement { + protected Type type; + protected String name; + protected Expression expression; + protected BaseStatement statements; + + public ForEachStatement(Type type, String name, Expression expression, BaseStatement statements) { + this.type = type; + this.name = name; + this.expression = expression; + this.statements = statements; + } + + public Type getType() { + return type; + } + + public String getName() { + return name; + } + + public Expression getExpression() { + return expression; + } + + public BaseStatement getStatements() { + return statements; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java new file mode 100644 index 00000000..280aacf2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.declaration.LocalVariableDeclaration; +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class ForStatement implements Statement { + protected LocalVariableDeclaration declaration; + protected BaseExpression init; + protected Expression condition; + protected BaseExpression update; + protected BaseStatement statements; + + public ForStatement(LocalVariableDeclaration declaration, Expression condition, BaseExpression update, BaseStatement statements) { + this.declaration = declaration; + this.condition = condition; + this.update = update; + this.statements = statements; + } + + public ForStatement(BaseExpression init, Expression condition, BaseExpression update, BaseStatement statements) { + this.init = init; + this.condition = condition; + this.update = update; + this.statements = statements; + } + + public LocalVariableDeclaration getDeclaration() { + return declaration; + } + + public void setDeclaration(LocalVariableDeclaration declaration) { + this.declaration = declaration; + } + + public BaseExpression getInit() { + return init; + } + + public void setInit(BaseExpression init) { + this.init = init; + } + + public Expression getCondition() { + return condition; + } + + public void setCondition(Expression condition) { + this.condition = condition; + } + + public BaseExpression getUpdate() { + return update; + } + + public BaseStatement getStatements() { + return statements; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ForStatement{" + declaration + " or " + init + "; " + condition + "; " + update + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java new file mode 100644 index 00000000..405273f0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class IfElseStatement extends IfStatement { + protected BaseStatement elseStatements; + + public IfElseStatement(Expression condition, BaseStatement statement, BaseStatement elseStatements) { + super(condition, statement); + this.elseStatements = elseStatements; + } + + public BaseStatement getElseStatements() { + return elseStatements; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java new file mode 100644 index 00000000..1beb3f9f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class IfStatement implements Statement { + protected Expression condition; + protected BaseStatement statements; + + public IfStatement(Expression condition, BaseStatement statements) { + this.condition = condition; + this.statements = statements; + } + + public Expression getCondition() { + return condition; + } + + public void setCondition(Expression condition) { + this.condition = condition; + } + + public BaseStatement getStatements() { + return statements; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java new file mode 100644 index 00000000..80ae048d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public class LabelStatement implements Statement { + protected String label; + protected Statement statement; + + public LabelStatement(String label, Statement statement) { + this.label = label; + this.statement = statement; + } + + public String getLabel() { + return label; + } + + public Statement getStatement() { + return statement; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LabelStatement{" + label + ": " + statement + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java new file mode 100644 index 00000000..c93de4d2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class LambdaExpressionStatement implements Statement { + protected Expression expression; + + public LambdaExpressionStatement(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LambdaExpressionStatement{" + expression + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java new file mode 100644 index 00000000..6989ccab --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.declaration.BaseLocalVariableDeclarator; +import org.jd.core.v1.model.javasyntax.declaration.LocalVariableDeclaration; +import org.jd.core.v1.model.javasyntax.type.Type; + +public class LocalVariableDeclarationStatement extends LocalVariableDeclaration implements Statement { + + public LocalVariableDeclarationStatement(Type type, BaseLocalVariableDeclarator localVariableDeclarators) { + super(type, localVariableDeclarators); + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LocalVariableDeclarationStatement{" + type + " " + localVariableDeclarators + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java new file mode 100644 index 00000000..31251c79 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +public class ReturnExpressionStatement implements Statement { + protected int lineNumber; + protected Expression expression; + + public ReturnExpressionStatement(Expression expression) { + this(expression.getLineNumber(), expression); + } + + public ReturnExpressionStatement(int lineNumber, Expression expression) { + this.lineNumber = lineNumber; + this.expression = expression; + assert expression != null; + } + + public int getLineNumber() { + return lineNumber; + } + + public void setLineNumber(int lineNumber) { + this.lineNumber = lineNumber; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + assert expression != null; + this.expression = expression; + } + + @SuppressWarnings("unchecked") + public T getGenericExpression() { + return (T)expression; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ReturnExpressionStatement{return " + expression + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java new file mode 100644 index 00000000..0a65d1ea --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public class ReturnStatement implements Statement { + public static final ReturnStatement RETURN = new ReturnStatement(); + + protected ReturnStatement() {} + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ReturnStatement{}"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statement.java new file mode 100644 index 00000000..a3100436 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statement.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public interface Statement extends BaseStatement { +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java new file mode 100644 index 00000000..2be4ee3d --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public interface StatementVisitor { + void visit(AssertStatement statement); + void visit(BreakStatement statement); + void visit(ByteCodeStatement statement); + void visit(CommentStatement statement); + void visit(ContinueStatement statement); + void visit(DoWhileStatement statement); + void visit(ExpressionStatement statement); + void visit(ForEachStatement statement); + void visit(ForStatement statement); + void visit(IfStatement statement); + void visit(IfElseStatement statement); + void visit(LabelStatement statement); + void visit(LambdaExpressionStatement statement); + void visit(LocalVariableDeclarationStatement statement); + void visit(ReturnExpressionStatement statement); + void visit(ReturnStatement statement); + void visit(Statements statement); + void visit(SwitchStatement statement); + void visit(SwitchStatement.DefaultLabel statement); + void visit(SwitchStatement.ExpressionLabel statement); + void visit(SwitchStatement.LabelBlock statement); + void visit(SwitchStatement.MultiLabelsBlock statement); + void visit(SynchronizedStatement statement); + void visit(ThrowStatement statement); + void visit(TryStatement statement); + void visit(TryStatement.Resource statement); + void visit(TryStatement.CatchClause statement); + void visit(TypeDeclarationStatement statement); + void visit(WhileStatement statement); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java new file mode 100644 index 00000000..9999b635 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.util.DefaultList; + +import java.util.List; + +public class Statements extends DefaultList implements BaseStatement { + + public Statements() {} + + public Statements(int capacity) { + super(capacity); + } + + public Statements(List list) { + super(list); + assert (list != null) && (list.size() > 1) : "Uses 'Statement' implementation instead"; + } + + @SuppressWarnings("unchecked") + public Statements(S statement, S... statements) { + super(statement, statements); + assert (statements != null) && (statements.length > 0) : "Uses 'Statement' implementation instead"; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java new file mode 100644 index 00000000..cb1105c7 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +import org.jd.core.v1.model.javasyntax.expression.Expression; + +import java.util.List; + +public class SwitchStatement implements Statement { + public static final DefaultLabel DEFAULT_LABEL = new DefaultLabel(); + + protected Expression condition; + protected List blocks; + + public SwitchStatement(Expression condition, List blocks) { + this.condition = condition; + this.blocks = blocks; + } + + public Expression getCondition() { + return condition; + } + + public void setCondition(Expression condition) { + this.condition = condition; + } + + public List getBlocks() { + return blocks; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + // --- Label --- // + public interface Label extends Statement {} + + public static class DefaultLabel implements Label { + protected DefaultLabel() {} + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "DefaultLabel"; + } + } + + public static class ExpressionLabel implements Label { + protected Expression expression; + + public ExpressionLabel(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ExpressionLabel{" + expression.toString() + '}'; + } + } + + // --- Block --- // + public static abstract class Block implements Statement { + protected BaseStatement statements; + + protected Block(BaseStatement statements) { + this.statements = statements; + } + + public BaseStatement getStatements() { + return statements; + } + } + + public static class LabelBlock extends Block { + protected Label label; + + public LabelBlock(Label label, BaseStatement statements) { + super(statements); + this.label = label; + } + + public Label getLabel() { + return label; + } + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "LabelBlock{label=" + label.toString() + '}'; + } + } + + public static class MultiLabelsBlock extends Block { + protected List
sections = buildSectionsVisitor.getSections(); + VisitorsHolder holder = new VisitorsHolder(); + UpdateSpacerBetweenMovableBlocksVisitor visitor = new UpdateSpacerBetweenMovableBlocksVisitor(); + + // Try to release constraints twice for each section + int max = sections.size() * 2; + + for (int loop=0; loop Quit loop + break; + } + } + + // Update the ratings + Section mostConstrainedSection = sections.get(0); + + for (Section section : sections) { + section.updateRate(); + + if (mostConstrainedSection.getRate() < section.getRate()) { + mostConstrainedSection = section; + } + } + + // Move fragments from the most constrained section + if (mostConstrainedSection.getRate() == 0) { + // No more constrained section -> Quit loop + break; + } + + if (! mostConstrainedSection.releaseConstraints(holder)) { + break; + } + } + + // Force layout + for (Section section : sections) { + section.layout(true); + } + + // Update fragments + fragments.clear(); + + for (Section section : sections) { + fragments.addAll(section.getFlexibleFragments()); + + FixedFragment fixedFragment = section.getFixedFragment(); + + if (fixedFragment != null) { + fragments.add(fixedFragment); + } + } + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/layouter/model/Section.java b/src/main/java/org/jd/core/v1/service/layouter/model/Section.java new file mode 100644 index 00000000..0a06650e --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/layouter/model/Section.java @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.layouter.model; + +import org.jd.core.v1.model.fragment.FixedFragment; +import org.jd.core.v1.model.fragment.FlexibleFragment; +import org.jd.core.v1.service.layouter.util.VisitorsHolder; +import org.jd.core.v1.service.layouter.visitor.AbstractSearchMovableBlockFragmentVisitor; +import org.jd.core.v1.service.layouter.visitor.AbstractStoreMovableBlockFragmentIndexVisitorAbstract; +import org.jd.core.v1.util.DefaultList; + +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +public class Section { + protected final DefaultList flexibleFragments; + protected final FixedFragment fixedFragment; + protected final Section previousSection; + protected Section nextSection; + protected final int targetLineCount; + protected int rate = 0; + + // Uses by "layout" method + protected int lastLineCount = -1; + protected int delta; + + public Section(DefaultList flexibleFragments, FixedFragment fixedFragment, Section previousSection) { + this.flexibleFragments = flexibleFragments; + this.fixedFragment = fixedFragment; + this.previousSection = previousSection; + + assert (flexibleFragments != null) && (flexibleFragments.size() > 0) : "Section must contain flexible fragments"; + + int previousLineNumber; + + if (previousSection == null) { + previousLineNumber = 1; + } else { + previousSection.nextSection = this; + previousLineNumber = previousSection.fixedFragment.getLastLineNumber(); + } + + if (fixedFragment == null) { + this.targetLineCount = 0; + } else { + this.targetLineCount = fixedFragment.getFirstLineNumber() - previousLineNumber; + } + } + + public DefaultList getFlexibleFragments() { return flexibleFragments; } + public FixedFragment getFixedFragment() { return fixedFragment; } + public Section getPreviousSection() { return previousSection; } + public Section getNextSection() { return nextSection; } + public int getRate() { return rate; } + + public void updateRate() { + rate = 0; + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + if (flexibleFragment.getInitialLineCount() > flexibleFragment.getLineCount()) { + rate += flexibleFragment.getInitialLineCount() - flexibleFragment.getLineCount(); + } + } + } + + /** + * @return true if a fragment has changed + */ + public boolean layout(boolean force) { + // Skip layout of last section + if (fixedFragment != null) { + // Compute line count + int currentLineCount = 0; + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + currentLineCount += flexibleFragment.getLineCount(); + } + + // Do not re-layout if nothing has changed + if (force || (lastLineCount != currentLineCount)) { + lastLineCount = currentLineCount; + + if (targetLineCount != currentLineCount) { + AutoGrowthList filteredFlexibleFragments = new AutoGrowthList(); + DefaultList constrainedFlexibleFragments = new DefaultList<>(flexibleFragments.size()); + + if (targetLineCount > currentLineCount) { + // Expands fragments + int oldDelta = delta = targetLineCount - currentLineCount; + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + if (flexibleFragment.getLineCount() < flexibleFragment.getMaximalLineCount()) { + // Keep only expandable fragments + filteredFlexibleFragments.get(flexibleFragment.getWeight()).add(flexibleFragment); + } + } + + // First, expand compacted fragments + for (DefaultList flexibleFragments : filteredFlexibleFragments) { + constrainedFlexibleFragments.clear(); + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + if (flexibleFragment.getLineCount() < flexibleFragment.getInitialLineCount()) { + // Store compacted flexibleFragments + constrainedFlexibleFragments.add(flexibleFragment); + } + } + + expand(constrainedFlexibleFragments, force); + if (delta == 0) break; + } + + // Next, expand all + if (delta > 0) { + for (DefaultList flexibleFragments : filteredFlexibleFragments) { + expand(flexibleFragments, force); + if (delta == 0) break; + } + } + + // Something changed ? + return oldDelta != delta; + } else { + // Compacts fragments + int oldDelta = delta = currentLineCount - targetLineCount; + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + if (flexibleFragment.getMinimalLineCount() < flexibleFragment.getLineCount()) { + // Keep only compactable fragments + filteredFlexibleFragments.get(flexibleFragment.getWeight()).add(flexibleFragment); + } + } + + // First, compact expanded fragments + for (DefaultList flexibleFragments : filteredFlexibleFragments) { + constrainedFlexibleFragments.clear(); + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + if (flexibleFragment.getLineCount() > flexibleFragment.getInitialLineCount()) { + // Store expanded flexibleFragments + constrainedFlexibleFragments.add(flexibleFragment); + } + } + + compact(constrainedFlexibleFragments, force); + if (delta == 0) break; + } + + // Next, compact all + if (delta > 0) { + for (DefaultList flexibleFragments : filteredFlexibleFragments) { + compact(flexibleFragments, force); + if (delta == 0) break; + } + } + + // Something changed ? + return oldDelta != delta; + } + } + } + } + + return false; + } + + protected void expand(DefaultList flexibleFragments, boolean force) { + int oldDelta = Integer.MAX_VALUE; + + while ((delta > 0) && (delta < oldDelta)) { + oldDelta = delta; + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + if (flexibleFragment.incLineCount(force)) { + if (--delta == 0) { + break; + } + } + } + } + } + + protected void compact(DefaultList flexibleFragments, boolean force) { + int oldDelta = Integer.MAX_VALUE; + + while ((delta > 0) && (delta < oldDelta)) { + oldDelta = delta; + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + if (flexibleFragment.decLineCount(force)) { + if (--delta == 0) { + break; + } + } + } + } + } + + public boolean releaseConstraints(VisitorsHolder holder) { + int flexibleCount = flexibleFragments.size(); + AbstractStoreMovableBlockFragmentIndexVisitorAbstract backwardSearchStartIndexesVisitor = holder.getBackwardSearchStartIndexesVisitor(); + AbstractStoreMovableBlockFragmentIndexVisitorAbstract forwardSearchEndIndexesVisitor = holder.getForwardSearchEndIndexesVisitor(); + AbstractSearchMovableBlockFragmentVisitor forwardSearchVisitor = holder.getForwardSearchVisitor(); + AbstractSearchMovableBlockFragmentVisitor backwardSearchVisitor = holder.getBackwardSearchVisitor(); + ListIterator iterator = flexibleFragments.listIterator(flexibleCount); + + backwardSearchStartIndexesVisitor.reset(); + forwardSearchEndIndexesVisitor.reset(); + + while (iterator.hasPrevious() && backwardSearchStartIndexesVisitor.isEnabled()) { + iterator.previous().accept(backwardSearchStartIndexesVisitor); + } + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + flexibleFragment.accept(forwardSearchEndIndexesVisitor); + if (! forwardSearchEndIndexesVisitor.isEnabled()) + break; + } + + int size = backwardSearchStartIndexesVisitor.getSize(); + Section nextSection = searchNextSection(forwardSearchVisitor); + + if ((size > 1) && (nextSection != null)) { + int index1 = flexibleCount - 1 - backwardSearchStartIndexesVisitor.getIndex(size/2); + int index2 = flexibleCount - 1 - backwardSearchStartIndexesVisitor.getIndex(0); + int nextIndex = forwardSearchVisitor.getIndex(); + + size = forwardSearchEndIndexesVisitor.getSize(); + + if (size > 1) { + int index3 = forwardSearchEndIndexesVisitor.getIndex(0) + 1; + int index4 = forwardSearchEndIndexesVisitor.getIndex(size/2) + 1; + Section previousSection = searchPreviousSection(backwardSearchVisitor); + + if (nextSection.getRate() > previousSection.getRate()) { + int index = previousSection.getFlexibleFragments().size() - backwardSearchVisitor.getIndex(); + previousSection.addFragmentsAtEnd(holder, index, extract(index3, index4)); + } else { + nextSection.addFragmentsAtBeginning(holder, nextIndex, extract(index1, index2)); + } + } else { + nextSection.addFragmentsAtBeginning(holder, nextIndex, extract(index1, index2)); + } + + return true; + } else { + size = forwardSearchEndIndexesVisitor.getSize(); + + if (size > 1) { + int index3 = forwardSearchEndIndexesVisitor.getIndex(0) + 1; + int index4 = forwardSearchEndIndexesVisitor.getIndex(size/2) + 1; + Section previousSection = searchPreviousSection(backwardSearchVisitor); + + if ((size > 1) && (previousSection != null)) { + int index = previousSection.getFlexibleFragments().size() - backwardSearchVisitor.getIndex(); + previousSection.addFragmentsAtEnd(holder, index, extract(index3, index4)); + return true; + } + } + } + + return false; + } + + protected Section searchNextSection(AbstractSearchMovableBlockFragmentVisitor visitor) { + Section section = getNextSection(); + + visitor.reset(); + + while (section != null) { + visitor.resetIndex(); + + for (FlexibleFragment flexibleFragment : section.getFlexibleFragments()) { + flexibleFragment.accept(visitor); + if (visitor.getDepth() == 0) + return section; + } + + section = section.getNextSection(); + } + + return null; + } + + protected Section searchPreviousSection(AbstractSearchMovableBlockFragmentVisitor visitor) { + Section section = getPreviousSection(); + + visitor.reset(); + + while (section != null) { + DefaultList flexibleFragments = section.getFlexibleFragments(); + ListIterator iterator = flexibleFragments.listIterator(flexibleFragments.size()); + + visitor.resetIndex(); + + while (iterator.hasPrevious()) { + iterator.previous().accept(visitor); + if (visitor.getDepth() == 0) + return section; + } + + section = section.getPreviousSection(); + } + + return null; + } + + protected void addFragmentsAtBeginning(VisitorsHolder holder, int index, List flexibleFragments) { + AbstractSearchMovableBlockFragmentVisitor visitor = holder.getForwardSearchVisitor(); + ListIterator iterator = flexibleFragments.listIterator(flexibleFragments.size()); + + // Extract separators + visitor.reset(); + + while (iterator.hasPrevious()) { + iterator.previous().accept(visitor); + if (visitor.getDepth() == 0) + break; + } + + assert (visitor.getIndex() < flexibleFragments.size()) && (visitor.getIndex() > 1); + + int index1 = flexibleFragments.size() + 1 - visitor.getIndex(); + + // Insert other fragments + this.flexibleFragments.addAll(index, flexibleFragments.subList(0, index1)); + // Insert separator at beginning + + this.flexibleFragments.addAll(index, flexibleFragments.subList(index1, flexibleFragments.size())); + + resetLineCount(); + } + + protected void addFragmentsAtEnd(VisitorsHolder holder, int index, List flexibleFragments) { + AbstractSearchMovableBlockFragmentVisitor visitor = holder.getForwardSearchVisitor(); + + // Extract separators + visitor.reset(); + + for (FlexibleFragment flexibleFragment : flexibleFragments) { + flexibleFragment.accept(visitor); + if (visitor.getDepth() == 2) + break; + } + + assert (visitor.getIndex() < flexibleFragments.size()) && (visitor.getIndex() > 1); + + int index1 = visitor.getIndex() - 1; + + // Insert other fragments + this.flexibleFragments.addAll(index, flexibleFragments.subList(0, index1)); + // Insert separator at end + this.flexibleFragments.addAll(index, flexibleFragments.subList(index1, flexibleFragments.size())); + + resetLineCount(); + } + + protected List extract(int index1, int index2) { + resetLineCount(); + + List subList = flexibleFragments.subList(index1, index2); + List fragmentsToMove = new DefaultList<>(subList); + + subList.clear(); + + return fragmentsToMove; + } + + protected void resetLineCount() { + for (FlexibleFragment flexibleFragment : flexibleFragments) { + flexibleFragment.resetLineCount(); + } + } + + @Override + public String toString() { + return "Section{flexibleFragments.size=" + flexibleFragments.size() + ", fixedFragment.firstLineNumber=" + (fixedFragment ==null ? "undefined" : fixedFragment.getFirstLineNumber()) + ", rate=" + rate + "}"; + } + + @SuppressWarnings("unchecked") + protected class AutoGrowthList implements Iterable>, Iterator> { + protected DefaultList[] elements = new DefaultList[21]; + protected int iteratorIndex; + + public void set(int index, DefaultList element) { + ensureCapacity(index); + elements[index] = element; + } + + public DefaultList get(int index) { + ensureCapacity(index); + + DefaultList element = elements[index]; + + if (element == null) { + elements[index] = element = new DefaultList<>(flexibleFragments.size()); + } + + return element; + } + + public void reverse() { + for (int index1=0, index2=elements.length-1; index1 tmp = elements[index1]; + elements[index1] = elements[index2]; + elements[index2] = tmp; + } + } + + protected void ensureCapacity(int minCapacity) { + if (elements.length <= minCapacity) { + DefaultList[] tmp = new DefaultList[minCapacity + 10]; + System.arraycopy(elements, 0, tmp, 0, elements.length); + elements = tmp; + } + } + + @Override + public Iterator> iterator() { + int length = elements.length; + + iteratorIndex = 0; + + while ((iteratorIndex < length) && (elements[iteratorIndex] == null)) { + iteratorIndex++; + } + + return this; + } + + @Override + public boolean hasNext() { + return iteratorIndex < elements.length; + } + + @Override + public DefaultList next() { + DefaultList element = elements[iteratorIndex++]; + int length = elements.length; + + while ((iteratorIndex < length) && (elements[iteratorIndex] == null)) { + iteratorIndex++; + } + + return element; + } + + @Override + public void remove() {} + } +} diff --git a/src/main/java/org/jd/core/v1/service/layouter/util/VisitorsHolder.java b/src/main/java/org/jd/core/v1/service/layouter/util/VisitorsHolder.java new file mode 100644 index 00000000..aaca21e2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/layouter/util/VisitorsHolder.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.layouter.util; + +import org.jd.core.v1.model.fragment.EndMovableBlockFragment; +import org.jd.core.v1.model.fragment.StartMovableBlockFragment; +import org.jd.core.v1.service.layouter.visitor.AbstractSearchMovableBlockFragmentVisitor; +import org.jd.core.v1.service.layouter.visitor.AbstractStoreMovableBlockFragmentIndexVisitorAbstract; + +public class VisitorsHolder { + protected AbstractSearchMovableBlockFragmentVisitor visitor7; + protected AbstractSearchMovableBlockFragmentVisitor visitor8; + protected AbstractStoreMovableBlockFragmentIndexVisitorAbstract visitor9; + protected AbstractStoreMovableBlockFragmentIndexVisitorAbstract visitor10; + + public AbstractSearchMovableBlockFragmentVisitor getForwardSearchVisitor() { + if (visitor7 == null) { + visitor7 = new AbstractSearchMovableBlockFragmentVisitor() { + @Override + public void visit(EndMovableBlockFragment fragment) { + depth--; + index++; + } + + @Override + public void visit(StartMovableBlockFragment fragment) { + depth++; + index++; + } + }; + } + return visitor7; + } + + public AbstractSearchMovableBlockFragmentVisitor getBackwardSearchVisitor() { + if (visitor8 == null) { + visitor8 = new AbstractSearchMovableBlockFragmentVisitor() { + @Override + public void visit(EndMovableBlockFragment fragment) { + depth++; + index++; + } + + @Override + public void visit(StartMovableBlockFragment fragment) { + depth--; + index++; + } + }; + } + return visitor8; + } + + public AbstractStoreMovableBlockFragmentIndexVisitorAbstract getBackwardSearchStartIndexesVisitor() { + if (visitor9 == null) { + visitor9 = new AbstractStoreMovableBlockFragmentIndexVisitorAbstract() { + @Override + public void visit(EndMovableBlockFragment fragment) { + if (enabled) { + depth++; + index++; + } + } + + @Override + public void visit(StartMovableBlockFragment fragment) { + if (enabled) { + if (depth == 0) { + enabled = false; + } else { + depth--; + if (depth == 0) { + storeIndex(); + } + index++; + } + } + } + }; + } + return visitor9; + } + + public AbstractStoreMovableBlockFragmentIndexVisitorAbstract getForwardSearchEndIndexesVisitor() { + if (visitor10 == null) { + visitor10 = new AbstractStoreMovableBlockFragmentIndexVisitorAbstract() { + @Override + public void visit(EndMovableBlockFragment fragment) { + if (enabled) { + if (depth == 0) { + enabled = false; + } else { + depth--; + if (depth == 0) { + storeIndex(); + } + index++; + } + } + } + + @Override + public void visit(StartMovableBlockFragment fragment) { + if (enabled) { + depth++; + index++; + } + } + }; + } + return visitor10; + } +} diff --git a/src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractSearchMovableBlockFragmentVisitor.java b/src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractSearchMovableBlockFragmentVisitor.java new file mode 100644 index 00000000..a4fd0780 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractSearchMovableBlockFragmentVisitor.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.layouter.visitor; + +import org.jd.core.v1.model.fragment.*; + +public abstract class AbstractSearchMovableBlockFragmentVisitor implements FragmentVisitor { + protected int depth; + protected int index; + + public void reset() { + this.depth = 1; + this.index = 0; + } + + public void resetIndex() { + this.index = 0; + } + + public int getDepth() { + return depth; + } + + public int getIndex() { + return index; + } + + @Override + public void visit(FlexibleFragment fragment) { + index++; + } + + @Override + public void visit(EndFlexibleBlockFragment fragment) { + index++; + } + + @Override + public void visit(EndMovableBlockFragment fragment) { + index++; + } + + @Override + public void visit(SpacerBetweenMovableBlocksFragment fragment) { + index++; + } + + @Override + public void visit(StartFlexibleBlockFragment fragment) { + index++; + } + + @Override + public void visit(StartMovableBlockFragment fragment) { + index++; + } + + @Override + public void visit(FixedFragment fragment) {} +} diff --git a/src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractStoreMovableBlockFragmentIndexVisitorAbstract.java b/src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractStoreMovableBlockFragmentIndexVisitorAbstract.java new file mode 100644 index 00000000..61f36438 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/layouter/visitor/AbstractStoreMovableBlockFragmentIndexVisitorAbstract.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.layouter.visitor; + +public abstract class AbstractStoreMovableBlockFragmentIndexVisitorAbstract extends AbstractSearchMovableBlockFragmentVisitor { + protected int[] indexes = new int[10]; + protected int size; + protected boolean enabled; + + public void reset() { + this.size = 0; + this.depth = 1; + this.index = 0; + this.enabled = true; + } + + public int getIndex(int i) { + return indexes[i]; + } + + public int getSize() { + return size; + } + + public boolean isEnabled() { + return enabled; + } + + protected void storeIndex() { + if (size == indexes.length) { + // Enlarge list... + int[] tmp = new int[size * 2]; + System.arraycopy(indexes, 0, tmp, 0, size); + indexes = tmp; + } + + indexes[size++] = index; + } +} diff --git a/src/main/java/org/jd/core/v1/service/layouter/visitor/BuildSectionsVisitor.java b/src/main/java/org/jd/core/v1/service/layouter/visitor/BuildSectionsVisitor.java new file mode 100644 index 00000000..2c2681ce --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/layouter/visitor/BuildSectionsVisitor.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.layouter.visitor; + +import org.jd.core.v1.model.fragment.*; +import org.jd.core.v1.service.layouter.model.Section; +import org.jd.core.v1.util.DefaultList; + +public class BuildSectionsVisitor implements FragmentVisitor { + protected DefaultList
sections = new DefaultList<>(); + protected DefaultList flexibleFragments = new DefaultList<>(); + protected Section previousSection = null; + + @Override public void visit(FlexibleFragment fragment) { flexibleFragments.add(fragment); } + @Override public void visit(EndFlexibleBlockFragment fragment) { flexibleFragments.add(fragment); } + @Override public void visit(EndMovableBlockFragment fragment) { flexibleFragments.add(fragment); } + @Override public void visit(SpacerBetweenMovableBlocksFragment fragment) { flexibleFragments.add(fragment); } + @Override public void visit(StartFlexibleBlockFragment fragment) { flexibleFragments.add(fragment); } + @Override public void visit(StartMovableBlockFragment fragment) { flexibleFragments.add(fragment); } + + @Override + public void visit(FixedFragment fragment) { + sections.add(previousSection = new Section(flexibleFragments, fragment, previousSection)); + flexibleFragments = new DefaultList<>(); + } + + public DefaultList
getSections() { + sections.add(new Section(flexibleFragments, null, previousSection)); + return sections; + } +} \ No newline at end of file diff --git a/src/main/java/org/jd/core/v1/service/layouter/visitor/UpdateSpacerBetweenMovableBlocksVisitor.java b/src/main/java/org/jd/core/v1/service/layouter/visitor/UpdateSpacerBetweenMovableBlocksVisitor.java new file mode 100644 index 00000000..9bf62bbe --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/layouter/visitor/UpdateSpacerBetweenMovableBlocksVisitor.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.layouter.visitor; + +import org.jd.core.v1.model.fragment.*; +import org.jd.core.v1.util.DefaultList; + + +public class UpdateSpacerBetweenMovableBlocksVisitor implements FragmentVisitor { + protected DefaultList blocks = new DefaultList<>(); + protected DefaultList spacers = new DefaultList<>(); + + protected int lastStartMovableBlockFragmentType; + protected SpacerBetweenMovableBlocksFragment lastSpacer; + protected int depth; + + public void reset() { + lastStartMovableBlockFragmentType = 0; + lastSpacer = null; + depth = 0; + } + + @Override + public void visit(StartMovableBlockFragment fragment) { + if (lastSpacer != null) { + // type=2 ==> Field + if ((lastStartMovableBlockFragmentType == 2) && (fragment.getType() == 2)) { + // 1 new line between 2 field declarations + lastSpacer.setInitialLineCount(1); + } else { + // otherwise, 2 new lines + lastSpacer.setInitialLineCount(2); + } + } + + if (depth != 0) { + blocks.add(fragment); + spacers.add(lastSpacer); + lastSpacer = null; + } + + lastStartMovableBlockFragmentType = fragment.getType(); + depth = 1; + } + + @Override + public void visit(EndMovableBlockFragment fragment) { + if (depth != 1) { + lastSpacer = spacers.remove(spacers.size()-1); + lastStartMovableBlockFragmentType = blocks.removeLast().getType(); + } + + depth = 0; + } + + @Override + public void visit(SpacerBetweenMovableBlocksFragment fragment) { + lastSpacer = fragment; + } + + @Override public void visit(FlexibleFragment fragment) {} + @Override public void visit(EndFlexibleBlockFragment fragment) {} + @Override public void visit(StartFlexibleBlockFragment fragment) {} + @Override public void visit(FixedFragment fragment) {} +} diff --git a/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/JavaFragmentToTokenProcessor.java b/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/JavaFragmentToTokenProcessor.java new file mode 100644 index 00000000..9d77e5a0 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/JavaFragmentToTokenProcessor.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.tokenizer.javafragmenttotoken; + +import org.jd.core.v1.model.javafragment.JavaFragment; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.model.processor.Processor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.visitor.TokenizeJavaFragmentVisitor; + +import java.util.List; + +/** + * Convert a list of fragments to a list of tokens.

+ * + * Input: List<{@link org.jd.core.v1.model.fragment.Fragment}>
+ * Output: List<{@link org.jd.core.v1.model.token.Token}>
+ */ +public class JavaFragmentToTokenProcessor implements Processor { + + @Override + public void process(Message message) throws Exception { + List fragments = message.getBody(); + TokenizeJavaFragmentVisitor visitor = new TokenizeJavaFragmentVisitor(fragments.size() * 3); + + // Create tokens + for (JavaFragment fragment : fragments) { + fragment.accept(visitor); + } + + message.setBody(visitor.getTokens()); + } +} diff --git a/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java b/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java new file mode 100644 index 00000000..2de9c546 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java @@ -0,0 +1,687 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.tokenizer.javafragmenttotoken.visitor; + +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.model.javafragment.*; +import org.jd.core.v1.model.token.*; +import org.jd.core.v1.util.DefaultList; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +public class TokenizeJavaFragmentVisitor implements JavaFragmentVisitor { + protected static final ImportNameComparator NAME_COMPARATOR = new ImportNameComparator(); + + protected static final KeywordToken DO = new KeywordToken("do"); + protected static final KeywordToken IMPORT = new KeywordToken("import"); + protected static final KeywordToken FOR = new KeywordToken("for"); + protected static final KeywordToken TRUE = new KeywordToken("true"); + protected static final KeywordToken TRY = new KeywordToken("try"); + protected static final KeywordToken WHILE = new KeywordToken("while"); + + protected static final List DO_TOKENS = Arrays.asList((Token)DO); + protected static final List EMPTY_FOR_TOKENS = Arrays.asList(FOR, TextToken.INFINITE_FOR); + protected static final List EMPTY_WHILE_TOKENS = Arrays.asList(WHILE, TextToken.SPACE, TextToken.LEFTROUNDBRACKET, TRUE, TextToken.RIGHTROUNDBRACKET); + protected static final List TRY_TOKENS = Arrays.asList((Token)TRY); + + protected KnownLineNumberTokenVisitor knownLineNumberTokenVisitor = new KnownLineNumberTokenVisitor(); + protected UnknownLineNumberTokenVisitor unknownLineNumberTokenVisitor = new UnknownLineNumberTokenVisitor(); + protected DefaultList tokens; + + public TokenizeJavaFragmentVisitor(int initialCapacity) { + this.tokens = new DefaultList<>(initialCapacity); + } + + public DefaultList getTokens() { + return tokens; + } + + @Override + public void visit(EndBlockFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_2); + tokens.add(EndBlockToken.END_BLOCK); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount())); + tokens.add(EndBlockToken.END_BLOCK); + } + } + + @Override + public void visit(EndBlockInParameterFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_2); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount())); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + } + } + + @Override + public void visit(EndBodyFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + break; + case 1: + if (fragment.getStartBodyFragment().getLineCount() == 0) { + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } else { + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + } + break; + case 2: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount()-1)); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } + } + + @Override + public void visit(EndBodyInParameterFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + tokens.add(TextToken.SPACE); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount()-1)); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + tokens.add(NewLineToken.NEWLINE_1); + } + } + + @Override public void visit(EndMovableJavaBlockFragment fragment) {} + + @Override + public void visit(EndSingleStatementBlockFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + switch (fragment.getStartSingleStatementBlockFragment().getLineCount()) { + case 0: + case 1: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + break; + default: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.SPACE); + break; + } + break; + case 1: + switch (fragment.getStartSingleStatementBlockFragment().getLineCount()) { + case 0: + tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + break; + } + break; + case 2: + switch (fragment.getStartSingleStatementBlockFragment().getLineCount()) { + case 0: + tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + tokens.add(NewLineToken.NEWLINE_2); + break; + default: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + } + break; + default: + switch (fragment.getStartSingleStatementBlockFragment().getLineCount()) { + case 0: + tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount())); + break; + default: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount()-1)); + break; + } + break; + } + } + + @Override + public void visit(EndStatementsBlockFragment fragment) { + int minimalLineCount = fragment.getGroup().getMinimalLineCount(); + + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + if (minimalLineCount == 0) { + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } else { + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.SPACE); + } + break; + case 2: + switch (minimalLineCount) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_2); + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount()-1)); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } + break; + default: + switch (minimalLineCount) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount())); + break; + case 1: + tokens.add(new NewLineToken(fragment.getLineCount())); + tokens.add(EndBlockToken.END_BLOCK); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount()-1)); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } + break; + } + } + + @Override + public void visit(ImportsFragment fragment) { + List imports = new DefaultList<>(fragment.getImports()); + + imports.sort(NAME_COMPARATOR); + + tokens.add(StartMarkerToken.IMPORT_STATEMENTS); + + for (ImportsFragment.Import imp : imports) { + tokens.add(IMPORT); + tokens.add(TextToken.SPACE); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, imp.getInternalName(), imp.getQualifiedName(), null, null)); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_1); + } + + tokens.add(EndMarkerToken.IMPORT_STATEMENTS); + } + + @Override + public void visit(LineNumberTokensFragment fragment) { + knownLineNumberTokenVisitor.reset(fragment.getFirstLineNumber()); + + for (Token token : fragment.getTokens()) { + token.accept(knownLineNumberTokenVisitor); + } + } + + @Override + public void visit(SpacerBetweenMembersFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_2); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount())); + } + } + + @Override + public void visit(SpacerFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_2); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount())); + } + } + + @Override + public void visit(SpaceSpacerFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_2); + break; + default: + tokens.add(new NewLineToken(fragment.getLineCount())); + } + } + + @Override + public void visit(StartBlockFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + case 2: + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_2); + break; + default: + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount())); + break; + } + } + + @Override + public void visit(StartBodyFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount()-1)); + break; + } + } + + @Override + public void visit(StartMovableJavaBlockFragment fragment) { + } + + @Override + public void visit(StartSingleStatementBlockFragment fragment) { + switch (fragment.getLineCount()) { + case 0: + tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + switch (fragment.getEndSingleStatementBlockFragment().getLineCount()) { + case 0: + tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + } + break; + case 2: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount() - 1)); + break; + } + } + + @Override + public void visit(StartStatementsBlockFragment fragment) { + int minimalLineCount = fragment.getGroup().getMinimalLineCount(); + + switch (fragment.getLineCount()) { + case 0: + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + if (minimalLineCount == 0) { + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + } else { + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } + break; + case 2: + switch (minimalLineCount) { + case 0: + tokens.add(NewLineToken.NEWLINE_2); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_2); + break; + default: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } + break; + default: + switch (minimalLineCount) { + case 0: + tokens.add(new NewLineToken(fragment.getLineCount())); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount())); + break; + default: + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount() - 1)); + } + break; + } + } + + @Override + public void visit(StartStatementsDoWhileBlockFragment fragment) { + visit(fragment, DO_TOKENS); + } + + @Override + public void visit(StartStatementsInfiniteForBlockFragment fragment) { + visit(fragment, EMPTY_FOR_TOKENS); + } + + @Override + public void visit(StartStatementsInfiniteWhileBlockFragment fragment) { + visit(fragment, EMPTY_WHILE_TOKENS); + } + + @Override + public void visit(StartStatementsTryBlockFragment fragment) { + visit(fragment, TRY_TOKENS); + } + + @Override + public void visit(TokensFragment fragment) { + for (Token token : fragment.getTokens()) { + token.accept(unknownLineNumberTokenVisitor); + } + } + + protected static class ImportNameComparator implements Comparator { + public int compare(ImportsFragment.Import tr1, ImportsFragment.Import tr2) { + return tr1.getQualifiedName().compareTo(tr2.getQualifiedName()); + } + public boolean equals(Object obj) { + return this.equals(obj); + } + } + + protected class KnownLineNumberTokenVisitor extends AbstractNopTokenVisitor { + public int currentLineNumber; + + public void reset(int firstLineNumber) { + this.currentLineNumber = firstLineNumber; + } + + @Override + public void visit(EndBlockToken token) { + assert token != EndBlockToken.END_BLOCK : "Unexpected EndBlockToken.END_BLOCK at this step. Uses 'JavaFragmentFactory.addEnd***(fragments)' instead"; + tokens.add(token); + } + + @Override + public void visit(LineNumberToken token) { + int lineNumber = token.getLineNumber(); + + if (lineNumber != Printer.UNKNOWN_LINE_NUMBER) { + if (currentLineNumber != Printer.UNKNOWN_LINE_NUMBER) { + switch (lineNumber - currentLineNumber) { + case 0: + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + break; + case 2: + tokens.add(NewLineToken.NEWLINE_2); + break; + default: + tokens.add(new NewLineToken(lineNumber - currentLineNumber)); + break; + } + } + + currentLineNumber = token.getLineNumber(); + tokens.add(token); + } + } + + @Override + public void visit(StartBlockToken token) { + assert token != StartBlockToken.START_BLOCK : "Unexpected StartBlockToken.START_BLOCK at this step. Uses 'JavaFragmentFactory.addStart***(fragments)' instead"; + tokens.add(token); + } + + @Override public void visit(BooleanConstantToken token) { tokens.add(token); } + @Override public void visit(CharacterConstantToken token) { tokens.add(token); } + @Override public void visit(DeclarationToken token) { tokens.add(token); } + @Override public void visit(EndMarkerToken token) { tokens.add(token); } + @Override public void visit(KeywordToken token) { tokens.add(token); } + @Override public void visit(NumericConstantToken token) { tokens.add(token); } + @Override public void visit(ReferenceToken token) { tokens.add(token); } + @Override public void visit(StartMarkerToken token) { tokens.add(token); } + @Override public void visit(StringConstantToken token) { tokens.add(token); } + @Override public void visit(TextToken token) { tokens.add(token); } + } + + protected class UnknownLineNumberTokenVisitor implements TokenVisitor { + @Override + public void visit(EndBlockToken token) { + assert token != EndBlockToken.END_BLOCK : "Unexpected EndBlockToken.END_BLOCK at this step. Uses 'JavaFragmentFactory.addEnd***(fragments)' instead"; + tokens.add(token); + } + + @Override + public void visit(LineNumberToken token) { + assert token.getLineNumber() == Printer.UNKNOWN_LINE_NUMBER : "LineNumberToken cannot have a known line number. Uses 'LineNumberTokensFragment' instead"; + } + + @Override + public void visit(StartBlockToken token) { + assert token != StartBlockToken.START_BLOCK : "Unexpected StartBlockToken.START_BLOCK at this step. Uses 'JavaFragmentFactory.addStart***(fragments)' instead"; + tokens.add(token); + } + + @Override public void visit(BooleanConstantToken token) { tokens.add(token); } + @Override public void visit(CharacterConstantToken token) { tokens.add(token); } + @Override public void visit(DeclarationToken token) { tokens.add(token); } + @Override public void visit(EndMarkerToken token) { tokens.add(token); } + @Override public void visit(KeywordToken token) { tokens.add(token); } + @Override public void visit(NewLineToken token) { tokens.add(token); } + @Override public void visit(NumericConstantToken token) { tokens.add(token); } + @Override public void visit(ReferenceToken token) { tokens.add(token); } + @Override public void visit(StartMarkerToken token) { tokens.add(token); } + @Override public void visit(StringConstantToken token) { tokens.add(token); } + @Override public void visit(TextToken token) { tokens.add(token); } + } + + protected void visit(StartStatementsBlockFragment fragment, Collection adds) { + int minimalLineCount = fragment.getGroup().getMinimalLineCount(); + + switch (fragment.getLineCount()) { + case 0: + tokens.addAll(adds); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + if (minimalLineCount == 0) { + tokens.add(NewLineToken.NEWLINE_1); + tokens.addAll(adds); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + } else { + tokens.addAll(adds); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } + break; + case 2: + switch (minimalLineCount) { + case 0: + tokens.add(NewLineToken.NEWLINE_2); + tokens.addAll(adds); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.add(NewLineToken.NEWLINE_1); + tokens.addAll(adds); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + break; + default: + tokens.addAll(adds); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + } + break; + default: + switch (minimalLineCount) { + case 0: + tokens.add(new NewLineToken(fragment.getLineCount())); + tokens.addAll(adds); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(TextToken.SPACE); + break; + case 1: + tokens.addAll(adds); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount())); + break; + default: + tokens.addAll(adds); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(new NewLineToken(fragment.getLineCount() - 1)); + } + break; + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/writer/WriteTokenProcessor.java b/src/main/java/org/jd/core/v1/service/writer/WriteTokenProcessor.java new file mode 100644 index 00000000..2c90ab66 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/writer/WriteTokenProcessor.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.writer; + +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.model.processor.Processor; +import org.jd.core.v1.model.token.Token; +import org.jd.core.v1.service.writer.visitor.PrintTokenVisitor; + +import java.util.List; + +/** + * Write a list of tokens to a {@link org.jd.core.v1.api.printer.Printer}.

+ * + * Input: List<{@link org.jd.core.v1.model.token.Token}>
+ * Output: -
+ */ +public class WriteTokenProcessor implements Processor { + + @Override + public void process(Message message) throws Exception { + Printer printer = message.getHeader("printer"); + List tokens = message.getBody(); + PrintTokenVisitor visitor = new PrintTokenVisitor(); + int maxLineNumber = message.getHeader("maxLineNumber"); + int majorVersion = message.getHeader("majorVersion"); + int minorVersion = message.getHeader("minorVersion"); + + printer.start(maxLineNumber, majorVersion, minorVersion); + visitor.start(printer, tokens); + + for (Token token : tokens) { + token.accept(visitor); + } + + visitor.end(); + printer.end(); + } +} diff --git a/src/main/java/org/jd/core/v1/service/writer/visitor/PrintTokenVisitor.java b/src/main/java/org/jd/core/v1/service/writer/visitor/PrintTokenVisitor.java new file mode 100644 index 00000000..521a22c7 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/writer/visitor/PrintTokenVisitor.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.writer.visitor; + +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.model.token.*; + +import java.util.List; + +public class PrintTokenVisitor implements TokenVisitor { + public static int UNKNOWN_LINE_NUMBER = Printer.UNKNOWN_LINE_NUMBER; + + protected SearchLineNumberVisitor searchLineNumberVisitor = new SearchLineNumberVisitor(); + + protected Printer printer; + protected List tokens; + protected int index; + protected int newLineCount; + + public void start(Printer printer, List tokens) { + this.printer = printer; + this.tokens = tokens; + this.index = 0; + this.newLineCount = 0; + printer.startLine(searchLineNumber()); + } + + public void end() { + printer.endLine(); + } + + @Override + public void visit(BooleanConstantToken token) { + prepareNewLine(); + printer.printKeyword(token.getValue() ? "true" : "false"); + index++; + } + + @Override + public void visit(CharacterConstantToken token) { + prepareNewLine(); + printer.printStringConstant('\'' + token.getCharacter() + '\'', token.getOwnerInternalName()); + index++; + } + + @Override + public void visit(DeclarationToken token) { + prepareNewLine(); + printer.printDeclaration(token.getFlags(), token.getInternalTypeName(), token.getName(), token.getDescriptor()); + index++; + } + + @Override + public void visit(StartBlockToken token) { + prepareNewLine(); + printer.printText(token.getText()); + printer.indent(); + if (token == StartBlockToken.START_RESOURCES_BLOCK) { + printer.indent(); + } + index++; + } + + @Override + public void visit(EndBlockToken token) { + printer.unindent(); + if (token == EndBlockToken.END_RESOURCES_BLOCK) { + printer.unindent(); + } + prepareNewLine(); + printer.printText(token.getText()); + index++; + } + + @Override + public void visit(StartMarkerToken token) { + prepareNewLine(); + printer.startMarker(token.getType()); + index++; + } + + @Override + public void visit(EndMarkerToken token) { + prepareNewLine(); + printer.endMarker(token.getType()); + index++; + } + + @Override + public void visit(NewLineToken token) { + newLineCount += token.getCount(); + index++; + } + + @Override + public void visit(KeywordToken token) { + prepareNewLine(); + printer.printKeyword(token.getKeyword()); + index++; + } + + @Override + public void visit(LineNumberToken token) { + index++; + } + + @Override + public void visit(NumericConstantToken token) { + prepareNewLine(); + printer.printNumericConstant(token.getText()); + index++; + } + + @Override + public void visit(ReferenceToken token) { + prepareNewLine(); + printer.printReference(token.getFlags(), token.getInternalTypeName(), token.getName(), token.getDescriptor(), token.getOwnerInternalName()); + index++; + } + + @Override + public void visit(StringConstantToken token) { + prepareNewLine(); + printer.printStringConstant('"' + token.getText() + '"', token.getOwnerInternalName()); + index++; + } + + @Override + public void visit(TextToken token) { + prepareNewLine(); + printer.printText(token.getText()); + index++; + } + + protected void prepareNewLine() { + if (newLineCount > 0) { + printer.endLine(); + + if (newLineCount > 2) { + printer.extraLine(newLineCount-2); + newLineCount = 2; + } + + if (newLineCount > 1) { + printer.startLine(UNKNOWN_LINE_NUMBER); + printer.endLine(); + } + + printer.startLine(searchLineNumber()); + newLineCount = 0; + } + } + + protected int searchLineNumber() { + // Backward search + searchLineNumberVisitor.reset(); + + for (int i=index; i>=0; i--) { + tokens.get(i).accept(searchLineNumberVisitor); + + if (searchLineNumberVisitor.lineNumber != UNKNOWN_LINE_NUMBER) + return searchLineNumberVisitor.lineNumber; + if (searchLineNumberVisitor.newLineCounter > 0) + break; + } + + // Forward search + searchLineNumberVisitor.reset(); + + int size = tokens.size(); + + for (int i=index; i 0) + break; + } + + return UNKNOWN_LINE_NUMBER; + } + + protected static class SearchLineNumberVisitor extends AbstractNopTokenVisitor { + public int lineNumber; + public int newLineCounter; + + public void reset() { + this.lineNumber = UNKNOWN_LINE_NUMBER; + this.newLineCounter = 0; + } + + @Override + public void visit(LineNumberToken token) { + lineNumber = token.getLineNumber(); + } + + @Override + public void visit(NewLineToken token) { + newLineCounter++; + } + } +} diff --git a/src/main/java/org/jd/core/v1/util/Base.java b/src/main/java/org/jd/core/v1/util/Base.java new file mode 100644 index 00000000..9fee2f23 --- /dev/null +++ b/src/main/java/org/jd/core/v1/util/Base.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.util; + +@SuppressWarnings("unchecked") +public interface Base { + default boolean isList() { + return false; + } + + default T getFirst() { + return (T)this; + } + + default DefaultList getList() { + return (DefaultList)this; + } + + default int size() { + return 1; + } +} diff --git a/src/main/java/org/jd/core/v1/util/DefaultList.java b/src/main/java/org/jd/core/v1/util/DefaultList.java new file mode 100644 index 00000000..253e5346 --- /dev/null +++ b/src/main/java/org/jd/core/v1/util/DefaultList.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.util; + +import java.util.ArrayList; +import java.util.Collection; + +@SuppressWarnings("unchecked") +public class DefaultList extends ArrayList { + protected static DefaultList EMPTY_LIST = new DefaultList() { + public Object set(int var1, Object var2) { + throw new UnsupportedOperationException(); + } + public void add(int var1, Object var2) { + throw new UnsupportedOperationException(); + } + public Object remove(int var1) { + throw new UnsupportedOperationException(); + } + }; + + public DefaultList() {} + + public DefaultList(int capacity) { + super(capacity); + } + + public DefaultList(Collection collection) { + super(collection); + } + + public DefaultList(E element, E... elements) { + super(elements.length + 1); + + add(element); + + for (E e : elements) { + add(e); + } + } + + public E getFirst() { + return (E)get(0); + } + + public E getLast() { + return (E)get(size()-1); + } + + public E removeFirst() { + return (E)remove(0); + } + + public E removeLast() { + return (E)remove(size()-1); + } + + public boolean isList() { + return true; + } + + public static final DefaultList emptyList() { + return EMPTY_LIST; + } +} diff --git a/src/main/java/org/jd/core/v1/util/DefaultStack.java b/src/main/java/org/jd/core/v1/util/DefaultStack.java new file mode 100644 index 00000000..1fc9a3fb --- /dev/null +++ b/src/main/java/org/jd/core/v1/util/DefaultStack.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.util; + +public class DefaultStack { + protected E[] elements; + protected int head; + + @SuppressWarnings("unchecked") + public DefaultStack() { + elements = (E[])new Object[16]; + head = 0; + } + + public DefaultStack(DefaultStack other) { + elements = other.elements.clone(); + head = other.head; + } + + public void clear() { + head = 0; + } + + public int size() { + return head; + } + + public boolean isEmpty() { + return head == 0; + } + + @SuppressWarnings("unchecked") + public void copy(DefaultStack other) { + if (elements.length < other.head) { + elements = (E[])new Object[other.head]; + } + + System.arraycopy(other.elements, 0, elements, 0, other.head); + head = other.head; + } + + @SuppressWarnings("unchecked") + public void push(E expression) { + if (head == elements.length) { + E[] tmp = (E[])new Object[elements.length * 2]; + System.arraycopy(elements, 0, tmp, 0, elements.length); + elements = tmp; + } + + elements[head++] = expression; + } + + public E pop() { + E e = elements[--head]; + elements[head] = null; + return e; + + //return elements[--head]; + } + + public E peek() { + return elements[head-1]; + } + + public void replace(E old, E nevv) { + int i = head - 1; + + while ((i >=0) && (elements[i] == old)) { + elements[i--] = nevv; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Stack{head="); + sb.append(head); + sb.append(", elements=["); + + if (head > 0) { + sb.append(elements[0]); + for (int i = 1; i < head; i++) { + sb.append(", "); + sb.append(elements[i]); + } + } + + sb.append("]}"); + + return sb.toString(); + } +} diff --git a/src/test/java/org/jd/core/v1/AggregateFieldsUtilTest.java b/src/test/java/org/jd/core/v1/AggregateFieldsUtilTest.java new file mode 100644 index 00000000..5f23949e --- /dev/null +++ b/src/test/java/org/jd/core/v1/AggregateFieldsUtilTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import org.jd.core.v1.model.javasyntax.declaration.FieldDeclarator; +import org.jd.core.v1.model.javasyntax.declaration.FieldDeclarators; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFieldDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.AggregateFieldsUtil; +import org.jd.core.v1.util.DefaultList; +import org.junit.Assert; +import org.junit.Test; + +@SuppressWarnings("unchecked") +public class AggregateFieldsUtilTest { + + @Test + public void test1() { + DefaultList fields = new DefaultList<>(); + + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"), 10)); + + DefaultList expected = new DefaultList<>(); + + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarators( + new FieldDeclarator("b"), + new FieldDeclarator("c") + ), 10)); + + AggregateFieldsUtil.aggregate(fields); + + Assert.assertEquals(expected, fields); + } + + @Test + public void test2() { + DefaultList fields = new DefaultList<>(); + + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"), 10)); + + DefaultList expected = new DefaultList<>(); + + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarators( + new FieldDeclarator("b"), + new FieldDeclarator("c") + ), 10)); + + AggregateFieldsUtil.aggregate(fields); + + Assert.assertEquals(expected, fields); + } + + @Test + public void test3() { + DefaultList fields = new DefaultList<>(); + + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"))); + + DefaultList expected = new DefaultList<>(); + + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarators( + new FieldDeclarator("b"), + new FieldDeclarator("c") + ), 10)); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"))); + + AggregateFieldsUtil.aggregate(fields); + + Assert.assertEquals(expected, fields); + } + + @Test + public void test4() { + DefaultList fields = new DefaultList<>(); + + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("e"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("f"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("g"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("h"), 15)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("i"))); + + DefaultList expected = new DefaultList<>(); + + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarators( + new FieldDeclarator("b"), + new FieldDeclarator("c"), + new FieldDeclarator("d"), + new FieldDeclarator("e"), + new FieldDeclarator("f") + ), 10)); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("g"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("h"), 15)); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("i"))); + + AggregateFieldsUtil.aggregate(fields); + + Assert.assertEquals(expected, fields); + } + + @Test + public void test5() { + DefaultList fields = new DefaultList<>(); + + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_LONG, new FieldDeclarator("d"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("e"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("f"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("g"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("h"), 15)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("i"))); + + DefaultList expected = new DefaultList<>(); + + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 10)); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_LONG, new FieldDeclarator("d"), 10)); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("e"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("f"), 10)); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("g"))); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("h"), 15)); + expected.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("i"))); + + AggregateFieldsUtil.aggregate(fields); + + Assert.assertEquals(expected, fields); + } +} diff --git a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java new file mode 100644 index 00000000..89eeb4e7 --- /dev/null +++ b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.classfile.ClassFile; +import org.jd.core.v1.model.classfile.attribute.Annotations; +import org.jd.core.v1.model.javasyntax.reference.*; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.AnnotationConverter; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.junit.Test; + +import java.io.InputStream; + +public class AnnotationConverterTest extends TestCase { + + @Test + @SuppressWarnings("unchecked") + public void test() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker factory = new ObjectTypeMaker(loader); + AnnotationConverter converter = new AnnotationConverter(factory); + DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AnnotatedClass"); + message.setHeader("loader", loader); + + deserializer.process(message); + + ClassFile classFile = message.getBody(); + + // Check class + assertNotNull(classFile); + + Annotations visibles = classFile.getAttribute("RuntimeVisibleAnnotations"); + Annotations invisibles = classFile.getAttribute("RuntimeInvisibleAnnotations"); + BaseAnnotationReference annotationReferences = converter.convert(visibles, invisibles); + + assertNotNull(annotationReferences); + assertTrue(annotationReferences instanceof AnnotationReferences); + + AnnotationReferences annotationReferenceList = (AnnotationReferences)annotationReferences; + + assertEquals(2, annotationReferenceList.size()); + + AnnotationReference annotationReference0 = annotationReferenceList.getFirst(); + + assertEquals("org/jd/core/test/annotation/Quality", annotationReference0.getType().getInternalName()); + assertEquals("Quality", annotationReference0.getType().getName()); + assertNotNull(annotationReference0.getElementValue()); + assertNull(annotationReference0.getElementValuePairs()); + assertEquals( + "ExpressionElementValue{" + + "FieldReferenceExpression{" + + "lastType=InnerObjectType{ObjectType{org/jd/core/test/annotation/Quality}.Lorg/jd/core/test/annotation/Quality$Level;}, " + + "expression=ObjectTypeReferenceExpression{InnerObjectType{ObjectType{org/jd/core/test/annotation/Quality}.Lorg/jd/core/test/annotation/Quality$Level;}}, " + + "name=HIGH, " + + "descriptor=org/jd/core/test/annotation/Quality$Level}" + + "}", + annotationReference0.getElementValue().toString()); + + AnnotationReference annotationReference1 = annotationReferenceList.get(1); + + assertEquals("org/jd/core/test/annotation/Author", annotationReference1.getType().getInternalName()); + assertEquals("Author", annotationReference1.getType().getName()); + assertNull(annotationReference1.getElementValue()); + assertNotNull(annotationReference1.getElementValuePairs()); + assertTrue(annotationReference1.getElementValuePairs() instanceof ElementValuePairs); + + ElementValuePairs elementValuePairArrayList = (ElementValuePairs)annotationReference1.getElementValuePairs(); + + assertEquals(2, elementValuePairArrayList.size()); + assertEquals("value", elementValuePairArrayList.getFirst().getName()); + assertEquals( + "AnnotationElementValue{" + + "type=ObjectType{org/jd/core/test/annotation/Name}, " + + "elementValue=null, " + + "elementValuePairs=ElementValuePairs{[" + + "ElementValuePair{name=salutation, elementValue=ExpressionElementValue{StringConstantExpression{\"Mr\"}}}, " + + "ElementValuePair{name=value, elementValue=ExpressionElementValue{StringConstantExpression{\"Donald\"}}}, " + + "ElementValuePair{name=last, elementValue=ExpressionElementValue{StringConstantExpression{\"Duck\"}}}" + + "]}" + + "}", + elementValuePairArrayList.get(0).getElementValue().toString()); + assertEquals("contributors", elementValuePairArrayList.get(1).getName()); + assertEquals( + "ElementValueArrayInitializerElementValue{" + + "ElementValues{[" + + "AnnotationElementValue{" + + "type=ObjectType{org/jd/core/test/annotation/Name}, " + + "elementValue=ExpressionElementValue{StringConstantExpression{\"Huey\"}}, " + + "elementValuePairs=null}, " + + "AnnotationElementValue{" + + "type=ObjectType{org/jd/core/test/annotation/Name}, " + + "elementValue=ExpressionElementValue{StringConstantExpression{\"Dewey\"}}, " + + "elementValuePairs=null}, " + + "AnnotationElementValue{" + + "type=ObjectType{org/jd/core/test/annotation/Name}, " + + "elementValue=ExpressionElementValue{StringConstantExpression{\"Louie\"}}, " + + "elementValuePairs=null}" + + "]}" + + "}", + elementValuePairArrayList.get(1).getElementValue().toString()); + } +} diff --git a/src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java b/src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java new file mode 100644 index 00000000..78782dde --- /dev/null +++ b/src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.classfile.ClassFile; +import org.jd.core.v1.model.classfile.Field; +import org.jd.core.v1.model.classfile.attribute.Annotations; +import org.jd.core.v1.model.classfile.attribute.ElementValueAnnotationValue; +import org.jd.core.v1.model.classfile.attribute.ElementValuePrimitiveType; +import org.jd.core.v1.model.classfile.constant.ConstantInteger; +import org.jd.core.v1.model.classfile.constant.ConstantUtf8; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.junit.Test; + +import java.io.InputStream; + +public class ClassFileDeserializerTest extends TestCase { + + @Test + public void testAnnotatedClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AnnotatedClass"); + message.setHeader("loader", loader); + + deserializer.process(message); + + ClassFile classFile = message.getBody(); + + // Check class + assertNotNull(classFile); + assertEquals("org/jd/core/test/AnnotatedClass", classFile.getInternalTypeName()); + assertEquals("java/util/ArrayList", classFile.getSuperTypeName()); + + Annotations invAttr = classFile.getAttribute("RuntimeInvisibleAnnotations"); + assertNotNull(invAttr.getAnnotations()); + assertEquals(2, invAttr.getAnnotations().length); + assertNotNull(invAttr.getAnnotations()[0].getElementValuePairs()); + assertEquals(1, invAttr.getAnnotations()[0].getElementValuePairs().length); + + ElementValueAnnotationValue annotationValue = invAttr.getAnnotations()[1].getElementValuePairs()[0].getElementValue(); + assertEquals("Lorg/jd/core/test/annotation/Name;", annotationValue.getAnnotationValue().getTypeName()); + assertNotNull(annotationValue.getAnnotationValue().getElementValuePairs()); + assertEquals(3, annotationValue.getAnnotationValue().getElementValuePairs().length); + assertEquals("salutation", annotationValue.getAnnotationValue().getElementValuePairs()[0].getElementName()); + + ElementValuePrimitiveType primitiveType = annotationValue.getAnnotationValue().getElementValuePairs()[1].getElementValue(); + ConstantUtf8 cu = primitiveType.getConstValue(); + assertEquals("Donald", cu.getValue()); + + // Check fields + assertNotNull(classFile.getFields()); + assertEquals(10, classFile.getFields().length); + + // Check 1st field + Field field = classFile.getFields()[1]; + assertEquals("b1", field.getName()); + assertEquals("B", field.getDescriptor()); + + Annotations attr = field.getAttribute("RuntimeVisibleAnnotations"); + assertNotNull(attr.getAnnotations()); + assertEquals(1, attr.getAnnotations().length); + assertNotNull(attr.getAnnotations()[0].getElementValuePairs()); + assertEquals(1, attr.getAnnotations()[0].getElementValuePairs().length); + assertEquals("b", attr.getAnnotations()[0].getElementValuePairs()[0].getElementName()); + + primitiveType = attr.getAnnotations()[0].getElementValuePairs()[0].getElementValue(); + ConstantInteger ci = primitiveType.getConstValue(); + assertEquals(-15, ci.getValue()); + + // Check 8th field + field = classFile.getFields()[8]; + assertEquals("str2", field.getName()); + assertEquals("Ljava/lang/String;", field.getDescriptor()); + + attr = field.getAttribute("RuntimeVisibleAnnotations"); + assertNotNull(attr.getAnnotations()); + assertEquals(1, attr.getAnnotations().length); + assertNotNull(attr.getAnnotations()[0].getElementValuePairs()); + assertEquals(1, attr.getAnnotations()[0].getElementValuePairs().length); + assertEquals("str", attr.getAnnotations()[0].getElementValuePairs()[0].getElementName()); + + primitiveType = attr.getAnnotations()[0].getElementValuePairs()[0].getElementValue(); + cu = primitiveType.getConstValue(); + assertEquals("str \u0083 \u0909 \u1109", cu.getValue()); + + // Check getters + assertNotNull(classFile.getMethods()); + assertEquals(3, classFile.getMethods().length); + + // Check constructor + assertEquals("", classFile.getMethods()[0].getName()); + assertEquals("()V", classFile.getMethods()[0].getDescriptor()); + assertNotNull(classFile.getMethods()[0].getAttribute("Code")); + } +} diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java new file mode 100644 index 00000000..5ce78199 --- /dev/null +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -0,0 +1,2030 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.jd.core.v1.util.PatternMaker; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class ClassFileToJavaSourceTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170Basic() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("serialVersionUID = 9506606333927794L;") != -1); + assertTrue(source.indexOf(".indexOf('B');") != -1); + + assertTrue(source.matches(PatternMaker.make("[ 26: 26]", "System.out.println(\"hello\");"))); + + assertTrue(source.indexOf("String str1 = \"3 == \" + (i + 1) + \" ?\";") != -1); + assertTrue(source.indexOf("String str2 = str1.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); + assertTrue(source.indexOf("char c2 = '€';") != -1); + assertTrue(source.indexOf("char c3 = '\\'';") != -1); + assertTrue(source.indexOf("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');") != -1); + assertTrue(source.indexOf("Class class3 = String.class, class2 = class3, class1 = class2;") != -1); + assertTrue(source.matches(PatternMaker.make("Class class5 = doSomething(class6 = String.class, args1 = args2 = new String[], class4 = class5;"))); + assertTrue(source.matches(PatternMaker.make("int j = 1, k[] = {1, l[][] = {"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + + assertTrue(source.matches(PatternMaker.make(": 58]", "return new String[] {s, s + '?'};"))); + + assertTrue(source.indexOf("if (this instanceof Object)") != -1); + + assertTrue(source.indexOf("int k = 50 / (25 + (i = 789));") != -1); + assertTrue(source.matches(PatternMaker.make(": 80]", "k = i += 100;"))); + assertTrue(source.matches(PatternMaker.make(": 85]", "i = ++this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 86]", "i = this.int78++;"))); + assertTrue(source.matches(PatternMaker.make(": 87]", "i *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 89]", "this.int78 = ++i;"))); + assertTrue(source.matches(PatternMaker.make(": 90]", "this.int78 = i++;"))); + assertTrue(source.matches(PatternMaker.make(": 91]", "this.int78 *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 93]", "long34 = ++long12;"))); + assertTrue(source.matches(PatternMaker.make(": 94]", "long34 = long12++;"))); + assertTrue(source.matches(PatternMaker.make(": 95]", "long34 *= 10L;"))); + assertTrue(source.matches(PatternMaker.make(": 97]", "i = (int)long12 + this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 99]", "i = k ^ 0xFF;"))); + assertTrue(source.matches(PatternMaker.make(": 100]", "i |= 0x7;"))); + + assertTrue(source.indexOf("int result;") != -1); + assertTrue(source.matches(PatternMaker.make(": 112]", "result = 1;"))); + assertTrue(source.matches(PatternMaker.make(": 114]", "int k = i;"))); + assertTrue(source.matches(PatternMaker.make(": 115]", "result = k + 2;"))); + assertTrue(source.matches(PatternMaker.make(": 118]", "result = this.short56;"))); + assertTrue(source.matches(PatternMaker.make(": 122]", "return result;"))); + assertTrue(source.matches(PatternMaker.make(": 126]", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make(": 128]", "i = (int)(Basic.long12 + long12) + this.int78 + int78;"))); + + assertTrue(source.indexOf("public static native int read();") != -1); + + assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); + + assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + + assertTrue(source.indexOf("()") == -1); + assertTrue(source.indexOf("null = ") == -1); + assertTrue(source.indexOf("NaND") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170NoDebugBasic() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("System.out.println(\"hello\");"))); + + assertTrue(source.matches(PatternMaker.make("String str1 = \"3 == \" + (paramInt + 1) + \" ?\";"))); + assertTrue(source.matches(PatternMaker.make("String str2 = \"abc \\\\b \\\\f \\\\n \\\\r \\\\t \\\\\\\" \\\\007 def\";"))); + assertTrue(source.matches(PatternMaker.make("char c2 = '€';"))); + assertTrue(source.matches(PatternMaker.make("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');"))); + assertTrue(source.matches(PatternMaker.make("Class clazz3 = String.class;"))); + assertTrue(source.matches(PatternMaker.make("Class clazz2 = clazz3;"))); + assertTrue(source.matches(PatternMaker.make("Class clazz1 = clazz2;"))); + assertTrue(source.indexOf("Class clazz5 = doSomething(clazz6 = String.class, arrayOfString1 = arrayOfString2 = new String[]") != -1); + + assertTrue(source.matches(PatternMaker.make("if (this instanceof Object)"))); + + assertTrue(source.matches(PatternMaker.make("this.int78 = 50 / (25 + (this.int78 = 789));"))); + + assertTrue(source.indexOf("()") == -1); + assertTrue(source.indexOf("null = ") == -1); + assertTrue(source.indexOf("NaND") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170Constructors() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Constructors"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 28]", "this.short123 = 1;"))); + + assertTrue(source.matches(PatternMaker.make(": 32]", "super(short56);"))); + assertTrue(source.matches(PatternMaker.make(": 33]", "this.short123 = 2;"))); + + assertTrue(source.matches(PatternMaker.make(": 37]", "this(short56);"))); + assertTrue(source.matches(PatternMaker.make(": 38]", "this.int78 = int78;"))); + assertTrue(source.matches(PatternMaker.make(": 39]", "this.short123 = 3;"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170IfElse() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/IfElse"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 12: 12]", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("[ 22: 22]", "if (\"abc\".isEmpty() && \"abc\".isEmpty())"))); + + assertTrue(source.matches(PatternMaker.make("[ 32: 32]", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("[ 34: 0]", "} else {"))); + + assertTrue(source.matches(PatternMaker.make("[ 44: 44]", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("[ 46: 46]", "} else if (this == null) {"))); + assertTrue(source.matches(PatternMaker.make("[ 48: 0]", "} else {"))); + + assertTrue(source.matches(PatternMaker.make("[ 58: 58]", "if (i == 0)"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 60]", "if (i == 1)"))); + + assertTrue(source.matches(PatternMaker.make("[ 71: 71]", "if (i == System.currentTimeMillis())"))); + assertTrue(source.matches(PatternMaker.make("[ 73: 73]", "} else if (i != System.currentTimeMillis()) {"))); + assertTrue(source.matches(PatternMaker.make("[ 75: 75]", "} else if (i > System.currentTimeMillis()) {"))); + + assertTrue(source.matches(PatternMaker.make("[ 123: 123]", "if (i == 4 && i == 5 && i == 6)"))); + + assertTrue(source.matches(PatternMaker.make("[ 135: 135]", "if (i == 3 || i == 5 || i == 6)"))); + assertTrue(source.matches(PatternMaker.make("[ 137: 137]", "} else if (i != 4 && i > 7 && i > 8) {"))); + assertTrue(source.matches(PatternMaker.make("[ 139: 0]", "} else {"))); + + assertTrue(source.matches(PatternMaker.make("[ 148: 148]", "if ((i == 1 && i == 2 && i == 3) || (i == 4 && i == 5 && i == 6) || (i == 7 && i == 8 && i == 9))"))); + assertTrue(source.matches(PatternMaker.make("[ 160: 160]", "if ((i == 1 || i == 2 || i == 3) && (i == 4 || i == 5 || i == 6) && (i == 7 || i == 8 || i == 9))"))); + + assertTrue(source.matches(PatternMaker.make("[ 172: 172]", "if ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))"))); + assertTrue(source.matches(PatternMaker.make("[ 184: 184]", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170Interface() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Interface"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("public interface Interface", "extends Serializable"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170While() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/While"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 15]", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23]", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42]", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("[ 113: 0]", "continue;"))); + assertTrue(source.matches(PatternMaker.make("[ 128: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 158: 0]", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232]", "while (++i < 10)"))); + assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); + assertFalse(source.matches(PatternMaker.make("[ 348: 0]", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348]", "continue;"))); + assertTrue(source.matches(PatternMaker.make("[ 404: 404]", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170DoWhile() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/DoWhile"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 24]", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32]", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44]", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46]", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72]", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77]", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79]", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98]", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108]", "while (i-- > 0.0F);"))); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170BreakContinue() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/BreakContinue"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 15: 15]", "if (i == 1)"))); + assertTrue(source.matches(PatternMaker.make("[ 16: 0]", "continue;"))); + assertTrue(source.matches(PatternMaker.make("[ 18: 18]", "if (i == 2)"))); + assertTrue(source.matches(PatternMaker.make("[ 19: 0]", "continue;"))); + + assertTrue(source.matches(PatternMaker.make("[ 31: 31]", "label18: while (i > 1)"))); + assertTrue(source.matches(PatternMaker.make("[ 37: 0]", "continue label18;"))); + assertTrue(source.matches(PatternMaker.make("[ 40: 0]", "break label18;"))); + + assertTrue(source.matches(PatternMaker.make("[ 54: 54]", "label17: while (i > 1)"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 63: 0]", "continue label17;"))); + + assertTrue(source.matches(PatternMaker.make("[ 78: 0]", "label13:"))); + assertTrue(source.matches(PatternMaker.make("[ 83: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 86: 0]", "break label13;"))); + + assertTrue(source.matches(PatternMaker.make("[ 101: 0]", "label15:", "do {"))); + assertTrue(source.matches(PatternMaker.make("[ 106: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 109: 0]", "break label15;"))); + + assertTrue(source.matches(PatternMaker.make("[ 123: 0]", "label24:", "do {"))); + assertTrue(source.matches(PatternMaker.make("[ 133: 0]", "continue label24;"))); + assertTrue(source.matches(PatternMaker.make("[ 135: 0]", "break label24;"))); + assertTrue(source.matches(PatternMaker.make("[ 138: 0]", "break label23;"))); + + assertTrue(source.matches(PatternMaker.make("[ 155: 0]", "label16:", "do {"))); + assertTrue(source.matches(PatternMaker.make("[ 162: 0]", "break label16;"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170For() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 16]", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 38]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 40]", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 50]", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 60]", "for (int i = 0;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 68]", "for (;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 76]", "for (int i = 0; i < 10;)"))); + assertTrue(source.matches(PatternMaker.make(": 84]", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 92]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("[ 100: 0]", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 108]", "for (int i = 0, j = i, size = 10; i < size; j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 118]", "int i = 0, j = i, size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 119]", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 120]", "j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 130]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 131]", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 132]", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 133]", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 134]", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 135]", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 145]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 147]", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 149]", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 151]", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 153]", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 155]", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 165]", "for (int i = 0; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 173]", "for (; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 181]", "for (int i = 0;; i++);"))); + assertTrue(source.matches(PatternMaker.make("[ 186: 0]", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 187]", "i++;"))); + assertTrue(source.matches(PatternMaker.make(": 193]", "for (int i = 0; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 199]", "for (int[] i = { 0 }; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 205]", "for (int i = 0, j = i, k = i; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 211]", "for (int[] i = { 0 }, j = i, k = j; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 217]", "for (int i = 0, j[] = { 1 }; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 223]", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 229]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("[ 230: 0]", "while (true);"))); + assertTrue(source.matches(PatternMaker.make(": 241]", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); + assertTrue(source.matches(PatternMaker.make("[ 249: 0]", "while (true) {"))); + assertTrue(source.matches(PatternMaker.make(": 260]", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make(": 385]", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 399]", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + + assertTrue(source.indexOf("[ 448: 448]") != -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170NoDebugFor() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make("for (byte b = 0;; b++)"))); + assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); + assertTrue(source.matches(PatternMaker.make("for (paramInt = 0; paramInt < 10; paramInt++)"))); + assertTrue(source.matches(PatternMaker.make("for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("for (String str : paramArrayOfString)"))); + assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk150For() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 16]", "for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make(": 84]", "while (paramInt < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 269]", "for (paramInt = 0; paramInt < 10; paramInt++)"))); + assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("[ 343: 0]", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 345]", "while (b < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 381]", "for (String str : paramArrayOfString)"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "for (String str : paramList)"))); + assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 423]", "for (byte b = 0; b < 3; b++)"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk160For() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.6.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 16]", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 84]", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 269]", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("[ 343: 0]", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 345]", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 381]", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testIbmJ9For() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-ibm-j9_vm.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 84]", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 269]", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("[ 343: 0]", "do"))); + assertTrue(source.matches(PatternMaker.make(": 345]", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 381]", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170Array() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + HashMap configuration = new HashMap<>(); + + configuration.put("realignLineNumbers", Boolean.FALSE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Array"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 12]", "int[] i1 = new int[1];"))); + assertTrue(source.matches(PatternMaker.make(": 13]", "int[][] i2 = new int[1][];"))); + assertTrue(source.matches(PatternMaker.make(": 14]", "int[][][] i3 = new int[1][][];"))); + assertTrue(source.matches(PatternMaker.make(": 15]", "int[][][] i4 = new int[1][2][];"))); + assertTrue(source.matches(PatternMaker.make(": 22]", "String[][][][] s5 = new String[1][2][][];"))); + + assertTrue(source.matches(PatternMaker.make(": 26]", "byte[] b1 = { 1, 2 } ;"))); + assertTrue(source.matches(PatternMaker.make(": 27]", "byte[][] b2 = { { 1, 2 } } ;"))); + assertTrue(source.matches(PatternMaker.make(": 28]", "byte[][][][] b3 = { { { 3, 4 } } } ;"))); + + assertTrue(source.matches(PatternMaker.make(": 48]", "testException1(new Exception[]", "{ new Exception(\"1\") } );"))); + + assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][]", "{ { 1 } ,"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk150Array() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + HashMap configuration = new HashMap<>(); + + configuration.put("realignLineNumbers", Boolean.FALSE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Array"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 13]", "int[][] arrayOfInt1 = new int[1][];"))); + assertTrue(source.matches(PatternMaker.make(": 30]", "int[][] arrayOfInt1 = { { 0, 1, 2"))); + + assertTrue(source.matches(PatternMaker.make(": 52]", "testException2(new Exception[][]", "{ { new Exception(\"1\")"))); + + assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][] { { 1,"))); + + assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][] { { 1,"))); + assertTrue(source.matches(PatternMaker.make(": 75]", "testInt3(new int[][][] { { { 0, 1"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170Assert() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Assert"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 16: 16]", "assert false : \"false\";"))); + assertTrue(source.matches(PatternMaker.make("[ 17: 17]", "assert i == 0 || i == 1;"))); + assertTrue(source.matches(PatternMaker.make("[ 18: 18]", "assert i == 2 && i < 3;"))); + + assertTrue(source.matches(PatternMaker.make("[ 34: 34]", "assert new BigDecimal(i) == BigDecimal.ONE;"))); + + assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk150Assert() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Assert"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 16: 16]", "assert false : \"false\";"))); + assertTrue(source.matches(PatternMaker.make("[ 17: 17]", "assert paramInt == 0 || paramInt == 1;"))); + assertTrue(source.matches(PatternMaker.make("[ 18: 18]", "assert paramInt == 2 && paramInt < 3;"))); + + assertTrue(source.matches(PatternMaker.make("[ 34: 34]", "assert new BigDecimal(paramInt) == BigDecimal.ONE;"))); + + assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk150AnonymousClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AnonymousClass"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 21]", "Object object = new Object()"))); + assertTrue(source.matches(PatternMaker.make(": 23]", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); + + assertTrue(source.matches(PatternMaker.make(": 37]", "final long l1 = System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 39]", "Enumeration enumeration = new Enumeration()"))); + assertTrue(source.matches(PatternMaker.make(": 40]", "Iterator i = AnonymousClass.this.list.iterator();"))); + assertTrue(source.matches(PatternMaker.make(": 44]", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); + assertTrue(source.indexOf("return this.i.next();") != -1); + assertTrue(source.matches(PatternMaker.make(": 52]", "test(enumeration, \"test\");"))); + assertTrue(source.matches(PatternMaker.make(": 55]", "System.out.println(\"end\");"))); + + assertTrue(source.matches(PatternMaker.make(": 67]", "if (s1 == s2 && i == 5)"))); + + assertTrue(source.matches(PatternMaker.make(": 90]", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 96]", "return (abc.equals(param2Object) || def.equals(param2Object) || str1.equals(param2Object) || str2.equals(param2Object));"))); + assertTrue(source.matches(PatternMaker.make(": 104]", "System.out.println(\"end\");"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170Switch() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Switch"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 15: 15]", "switch (i)"))); + assertTrue(source.matches(PatternMaker.make("[ 16: 0]", "case 0:"))); + assertTrue(source.matches(PatternMaker.make("[ 17: 17]", "System.out.println(\"0\");"))); + assertTrue(source.matches(PatternMaker.make("[ 18: 0]", "break;"))); + + assertTrue(source.matches(PatternMaker.make("[ 34: 0]", "case 0:"))); + assertTrue(source.matches(PatternMaker.make("[ 35: 35]", "System.out.println(\"0\");"))); + assertTrue(source.matches(PatternMaker.make("[ 36: 0]", "case 1:"))); + + assertTrue(source.matches(PatternMaker.make("[ 56: 0]", "default:"))); + + assertTrue(source.matches(PatternMaker.make("[ 110: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 111: 0]", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("[ 112: 112]", "System.out.println(\"1\");"))); + assertTrue(source.matches(PatternMaker.make("[ 113: 113]", "throw new RuntimeException(\"boom\");"))); + + assertTrue(source.matches(PatternMaker.make("[ 134: 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make("[ 171: 0]", "case 3:"))); + assertTrue(source.matches(PatternMaker.make("[ 172: 0]", "case 4:"))); + assertTrue(source.matches(PatternMaker.make("[ 173: 173]", "System.out.println(\"3 or 4\");"))); + assertTrue(source.matches(PatternMaker.make("[ 174: 0]", "break;"))); + + assertTrue(source.matches(PatternMaker.make("[ 265: 0]", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("[ 266: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 267: 0]", "default:"))); + + assertTrue(source.matches(PatternMaker.make("[ 283: 0]", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("[ 284: 0]", "case 2:"))); + assertTrue(source.matches(PatternMaker.make("[ 285: 0]", "case 3:"))); + assertTrue(source.matches(PatternMaker.make("[ 286: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 288: 0]", "default:"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170AdvancedSwitch() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AdvancedSwitch"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 13: 13]", "A,", "B,", "C;"))); + + assertTrue(source.matches(PatternMaker.make("[ 19: 19]", "switch (te)"))); + assertTrue(source.matches(PatternMaker.make("[ 20: 0]", "case A:"))); + assertTrue(source.matches(PatternMaker.make("[ 22: 0]", "case B:"))); + assertTrue(source.matches(PatternMaker.make("[ 25: 0]", "case C:"))); + + assertTrue(source.matches(PatternMaker.make("[ 38: 38]", "switch (str)"))); + assertTrue(source.matches(PatternMaker.make("[ 39: 0]", "case \"One\":"))); + assertTrue(source.matches(PatternMaker.make("[ 40: 40]", "System.out.println(1);"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testEclipseJavaCompiler321Switch() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Switch"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 239: 239]") != -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testEclipseJavaCompiler3130Switch() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Switch"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 239: 239]") != -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk118TernaryOperator() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TernaryOperator"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 13]", "this.str ="))); + assertTrue(source.matches(PatternMaker.make(": 14]", "(s == null) ?"))); + assertTrue(source.matches(PatternMaker.make(": 15]", "\"1\""))); + assertTrue(source.matches(PatternMaker.make(": 16]", "\"2\";"))); + assertTrue(source.matches(PatternMaker.make(": 24]", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); + assertTrue(source.matches(PatternMaker.make(": 34]", "return (s != s || time < time) ? false : true;"))); + assertTrue(source.matches(PatternMaker.make(": 40]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 60]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 71]", "if ((s1 == null) ? false : (s1.length() > 0))"))); + assertTrue(source.matches(PatternMaker.make(": 82]", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 126]", "if (s1 == null && false)"))); + assertTrue(source.matches(PatternMaker.make(": 137]", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 148]", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170TernaryOperator() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TernaryOperator"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 13]", "this.str = (s == null) ? \"1\" : \"2\";"))); + assertTrue(source.matches(PatternMaker.make(": 24]", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); + assertTrue(source.matches(PatternMaker.make(": 34]", "return (s == s && time >= time);"))); + assertTrue(source.matches(PatternMaker.make(": 40]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 60]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 71]", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 82]", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 126]", "if (s1 == null);"))); + assertTrue(source.matches(PatternMaker.make(": 137]", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 148]", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170TryWithResources() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryWithResources"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 12]", "try (FileInputStream input = new FileInputStream(path))"))); + + assertTrue(source.matches(PatternMaker.make(": 49]", "try (FileInputStream input = new FileInputStream(path))"))); + assertTrue(source.matches(PatternMaker.make(": 57]", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 59]", "System.out.println(\"finally\");"))); + + assertTrue(source.matches(PatternMaker.make(": 121]", "try(FileInputStream input = new FileInputStream(pathIn);"))); + assertTrue(source.matches(PatternMaker.make(": 122]", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); + assertTrue(source.matches(PatternMaker.make(": 123]", "FileOutputStream output = new FileOutputStream(pathOut);"))); + assertTrue(source.matches(PatternMaker.make(": 124]", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); + assertTrue(source.matches(PatternMaker.make(": 132]", "if (data == -7)"))); + assertTrue(source.matches(PatternMaker.make(": 133]", "return 1;"))); + assertTrue(source.matches(PatternMaker.make(": 142]", "return 2;"))); + assertTrue(source.matches(PatternMaker.make(": 144]", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 150]", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 152]", "System.out.println(\"finally, before loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 156]", "System.out.println(\"finally, after loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 159]", "System.out.println(\"finally\");"))); + assertTrue(source.matches(PatternMaker.make(": 162]", "return 3;"))); + + assertTrue(source.indexOf("[ 162: 162]") != -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk180TryWithResources() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryWithResources"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 12]", "try (FileInputStream input = new FileInputStream(path))"))); + + assertTrue(source.matches(PatternMaker.make(": 49]", "try (FileInputStream input = new FileInputStream(path))"))); + assertTrue(source.matches(PatternMaker.make(": 57]", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 59]", "System.out.println(\"finally\");"))); + + assertTrue(source.matches(PatternMaker.make(": 121]", "try(FileInputStream input = new FileInputStream(pathIn);"))); + assertTrue(source.matches(PatternMaker.make(": 122]", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); + assertTrue(source.matches(PatternMaker.make(": 123]", "FileOutputStream output = new FileOutputStream(pathOut);"))); + assertTrue(source.matches(PatternMaker.make(": 124]", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); + assertTrue(source.matches(PatternMaker.make(": 132]", "if (data == -7)"))); + assertTrue(source.matches(PatternMaker.make(": 133]", "return 1;"))); + assertTrue(source.matches(PatternMaker.make(": 142]", "return 2;"))); + assertTrue(source.matches(PatternMaker.make(": 144]", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 150]", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 152]", "System.out.println(\"finally, before loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 156]", "System.out.println(\"finally, after loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 159]", "System.out.println(\"finally\");"))); + assertTrue(source.matches(PatternMaker.make(": 162]", "return 3;"))); + + assertTrue(source.indexOf("[ 162: 162]") != -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170Synchronised() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Synchronized"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 11]", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 13]", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 15]", "return 2;"))); + + assertTrue(source.matches(PatternMaker.make(": 20]", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 22]", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 23]", "return 2;"))); + + assertTrue(source.matches(PatternMaker.make(": 29]", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 31]", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 73]", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 75]", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 76]", "throw new RuntimeException();"))); + + assertTrue(source.matches(PatternMaker.make(": 95]", "synchronized (s)"))); + assertTrue(source.matches(PatternMaker.make(": 97]", "return subContentEquals(s);"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("[ 45: 45]", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + + assertTrue(source.indexOf("[ 888: 888]") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); + assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + assertTrue(source.indexOf("[ 400: 0] inFinally();") == -1); + + assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + + assertTrue(source.indexOf("[ 888: 888]") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); + assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + + assertTrue(source.indexOf("[ 888: 888]") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk118TryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + + assertTrue(source.indexOf("[ 902: 902]") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk131TryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.3.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + + assertTrue(source.indexOf("[ 902: 902]") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170TryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 192]", "catch (RuntimeException e) {}"))); + assertTrue(source.matches(PatternMaker.make("[ 204: 0]", "finally {}"))); + + assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + + assertTrue(source.indexOf("[ 902: 902]") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170AnnotatedClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + // PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AnnotatedClass"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("@Quality(Quality.Level.HIGH)") != -1); + assertTrue(source.indexOf("@Author(value = @Name(salutation = \"Mr\", value = \"Donald\", last = \"Duck\"), contributors = {@Name(\"Huey\"), @Name(\"Dewey\"), @Name(\"Louie\")})") != -1); + assertTrue(source.indexOf("@Value(z = true)") != -1); + assertTrue(source.indexOf("@Value(b = -15)") != -1); + assertTrue(source.indexOf("@Value(s = -15)") != -1); + assertTrue(source.indexOf("@Value(i = 1)") != -1); + assertTrue(source.indexOf("@Value(l = 1234567890123456789L)") != -1); + assertTrue(source.indexOf("@Value(f = 123.456F)") != -1); + assertTrue(source.indexOf("@Value(d = 789.101112D)") != -1); + assertTrue(source.indexOf("@Value(str = \"str\")") != -1); + assertTrue(source.indexOf("@Value(str = \"str \u0083 उ ᄉ\")") != -1); + assertTrue(source.indexOf("@Value(clazz = String.class)") != -1); + assertTrue(source.indexOf("public void ping(@Deprecated Writer writer, @Deprecated @Value(str = \"localhost\") String host, long timeout)") != -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170AnonymousClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + // PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AnonymousClass"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 21]", "Object obj = new Object()"))); + assertTrue(source.matches(PatternMaker.make(": 23]", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); + + assertTrue(source.matches(PatternMaker.make(": 39]", "Enumeration e = new Enumeration()"))); + assertTrue(source.matches(PatternMaker.make(": 40]", "Iterator i = AnonymousClass.this.list.iterator();"))); + assertTrue(source.matches(PatternMaker.make(": 44]", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); + + assertTrue(source.matches(PatternMaker.make(": 61]", "final int i = s1.length();"))); + assertTrue(source.matches(PatternMaker.make(": 63]", "System.out.println(\"2\" + new StringWrapper(123456L)"))); + assertTrue(source.matches(PatternMaker.make(": 67]", "if (s1 == s2 && i == 5)"))); + assertTrue(source.matches(PatternMaker.make("[ 72: 0]", "} + \"3\");"))); + + assertTrue(source.matches(PatternMaker.make(": 81]", "final Object abc = \"abc\";"))); + assertTrue(source.matches(PatternMaker.make(": 82]", "final Object def = \"def\";"))); + assertTrue(source.matches(PatternMaker.make(": 84]", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 90]", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 96]", "return (abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj));"))); + assertTrue(source.matches(PatternMaker.make(": 100]", "return (abc.equals(obj) || def.equals(obj));"))); + assertTrue(source.matches(PatternMaker.make("[ 102: 0]", "};"))); + + assertTrue(source.matches(PatternMaker.make(": 111]", "this.l = l & 0x80L;"))); + + assertTrue(source.indexOf("} ;") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170GenericClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/GenericClass"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("public class GenericClass, T7 extends Map, T8 extends Map, T9 extends T8>") != -1); + assertTrue(source.indexOf("extends ArrayList") != -1); + assertTrue(source.indexOf("implements Serializable, Comparable") != -1); + + assertTrue(source.matches(PatternMaker.make("[ 26: 26]", "public List> list1 = new ArrayList();"))); + assertTrue(source.indexOf("public List> list2;") != -1); + assertTrue(source.matches(PatternMaker.make("[ 31: 31]", "list2 = new ArrayList();"))); + + assertTrue(source.indexOf("public void fromArrayToCollection(T[] a, Collection c)") != -1); + assertTrue(source.indexOf("public void copy(List dest, List src)") != -1); + assertTrue(source.indexOf("public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException") != -1); + assertTrue(source.indexOf("public List print(List list) throws T2, InvalidParameterException") != -1); + + assertTrue(source.matches(PatternMaker.make(": 100]", "return (T1)call(0);"))); + assertTrue(source.matches(PatternMaker.make(": 104]", "return (T1)this;"))); + + assertTrue(source.indexOf("[ 104: 104]") != -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170AnnotationAuthor() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/annotation/Author"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "public @interface Author"))); + assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "Name value();"))); + assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "Name[] contributors() default {};"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170AnnotationValue() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/annotation/Value"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "@Retention(RetentionPolicy.RUNTIME)"))); + assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})"))); + assertTrue(source.matches(PatternMaker.make("[ 10: 0]", "public @interface Value {"))); + assertTrue(source.matches(PatternMaker.make("[ 11: 0]", "boolean z() default true;"))); + assertTrue(source.matches(PatternMaker.make("[ 13: 0]", "byte b() default 1;"))); + assertTrue(source.matches(PatternMaker.make("[ 25: 0]", "String str() default \"str\";"))); + assertTrue(source.matches(PatternMaker.make("[ 27: 0]", "Class clazz() default Object.class;"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170OuterClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //ClassPathLoader loader = new ClassPathLoader(); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/OuterClass"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 10]", "protected int outerField1 = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 11]", "protected String[] outerField2 = { \"0\" };"))); + + assertTrue(source.indexOf("final int localVariable1 = param1;") != -1); + assertTrue(source.indexOf("final String[] localVariable2 = param2;") != -1); + + assertTrue(source.matches(PatternMaker.make(": 21]", "InnerClass innerClass = new InnerClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 22]", "innerClass.innerMethod(localVariable1, localVariable2);"))); + assertTrue(source.matches(PatternMaker.make(": 24]", "StaticInnerClass staticInnerClass = new StaticInnerClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 25]", "staticInnerClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 27]", "InnerClass anonymousClass = new InnerClass(param1, param2)"))); + assertTrue(source.indexOf("public void innerMethod(int param1, String... param2)") != -1); + assertTrue(source.matches(PatternMaker.make(": 30]", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 32]", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 33]", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 35]", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 36]", "this.innerField2 = localVariable2;"))); + + assertTrue(source.matches(PatternMaker.make(": 39]", "anonymousClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 41]", "StaticInnerClass staticAnonymousClass = new StaticInnerClass(param1, param2)"))); + assertTrue(source.matches(PatternMaker.make(": 44]", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 46]", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 47]", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 49]", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 50]", "this.innerField2 = localVariable2;"))); + + assertTrue(source.matches(PatternMaker.make(": 53]", "staticAnonymousClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 55]", "InnerEnum.A.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make("[ 56: 0]", "class LocalClass"))); + assertTrue(source.matches(PatternMaker.make(": 58]", "protected int innerField1 = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 59]", "protected String[] innerField2 = { \"0\" } ;"))); + assertTrue(source.matches(PatternMaker.make(": 69]", "this.innerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 70]", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 72]", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 73]", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 75]", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 76]", "this.innerField2 = localVariable2;"))); + assertTrue(source.matches(PatternMaker.make(": 94]", "LocalClass localClass = new LocalClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 95]", "localClass.localMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 114]", "this(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 144]", "this(param1, param2);"))); + + assertTrue(source.matches(PatternMaker.make(": 158]", "A,", "B,", "C;"))); + assertTrue(source.indexOf("[ 182: 182]") != -1); + + assertTrue(source.matches(PatternMaker.make("public class InnerInnerClass", "{", "}"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk170Enum() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Enum"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 5]", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + + assertTrue(source.matches(PatternMaker.make(": 9]", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17]", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20]", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.indexOf("this.mass = mass;") != -1); + assertTrue(source.matches(PatternMaker.make(": 27]", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37]", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49]", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50]", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51]", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52]", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + + assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); + + assertTrue(source.indexOf("public static final enum") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk118Basic() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make(": 126]", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return String.valueOf(str) + str;"))); + assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk142Basic() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.4.2.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 18]", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19]", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); + assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk180Lambda() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Lambda"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 16]", "list.forEach(System.out::println);"))); + assertTrue(source.matches(PatternMaker.make(": 20]", "list.stream().filter(s -> (s != null)).forEach(s -> System.out.println(s));"))); + assertTrue(source.indexOf("Predicate filter = s -> (s.length() == length);") != -1); + assertTrue(source.indexOf("Consumer println = s -> System.out.println(s);") != -1); + assertTrue(source.matches(PatternMaker.make(": 27]", "list.stream().filter(filter).forEach(println);"))); + assertTrue(source.matches(PatternMaker.make(": 31]", "((Map)list.stream()"))); + assertTrue(source.matches(PatternMaker.make(": 32]", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))"))); + assertTrue(source.matches(PatternMaker.make(": 33]", ".forEach((key, value) ->"))); + assertTrue(source.matches(PatternMaker.make(": 48]", "Thread thread = new Thread(() -> {"))); + assertTrue(source.matches(PatternMaker.make(": 58]", "Consumer staticMethodReference = String::valueOf;"))); + assertTrue(source.matches(PatternMaker.make(": 59]", "BiFunction methodReference = String::compareTo;"))); + assertTrue(source.matches(PatternMaker.make(": 60]", "Supplier instanceMethodReference = s::toString;"))); + assertTrue(source.matches(PatternMaker.make(": 61]", "Supplier constructorReference = String::new;"))); + assertTrue(source.matches(PatternMaker.make(": 65]", "MethodType mtToString = MethodType.methodType(String.class);"))); + assertTrue(source.matches(PatternMaker.make(": 66]", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); + assertTrue(source.matches(PatternMaker.make(": 67]", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/CodeExceptionComparatorTest.java b/src/test/java/org/jd/core/v1/CodeExceptionComparatorTest.java new file mode 100644 index 00000000..180d95bd --- /dev/null +++ b/src/test/java/org/jd/core/v1/CodeExceptionComparatorTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.model.classfile.attribute.CodeException; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ControlFlowGraphMaker; +import org.junit.Test; + +import java.util.Arrays; + +public class CodeExceptionComparatorTest extends TestCase { + @Test + public void test() throws Exception { + // CodeException(int index, int startPc, int endPc, int handlerPc, int catchType) + CodeException ce0 = new CodeException(0, 10, 80, 50, 1); + CodeException ce1 = new CodeException(1, 20, 30, 35, 2); + CodeException ce2 = new CodeException(2, 20, 25, 35, 3); + CodeException ce3 = new CodeException(3, 25, 30, 40, 0); + CodeException ce4 = new CodeException(4, 10, 30, 60, 0); + + CodeException[] codeExceptions = { ce0, ce1, ce2, ce3, ce4 }; + + ControlFlowGraphMaker.CodeExceptionComparator comparator = new ControlFlowGraphMaker.CodeExceptionComparator(); + + Arrays.sort(codeExceptions, comparator); + + assertTrue(codeExceptions[0] == ce4); + assertTrue(codeExceptions[1] == ce0); + assertTrue(codeExceptions[2] == ce2); + assertTrue(codeExceptions[3] == ce1); + } +} \ No newline at end of file diff --git a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java new file mode 100644 index 00000000..af90ee54 --- /dev/null +++ b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java @@ -0,0 +1,2693 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.classfile.Method; +import org.jd.core.v1.model.javasyntax.CompilationUnit; +import org.jd.core.v1.model.javasyntax.declaration.BaseTypeDeclaration; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.Loop; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.processor.ConvertClassFileProcessor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.*; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.util.ControlFlowGraphPlantUMLWriter; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.BitSet; +import java.util.HashSet; +import java.util.List; + +import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; +import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.invokeGetter; + +public class ControlFlowGraphTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ConvertClassFileProcessor converter = new ConvertClassFileProcessor(); + protected ClassPathLoader loader = new ClassPathLoader(); + protected ObjectTypeMaker factory = new ObjectTypeMaker(loader); + protected SignatureParser parser = new SignatureParser(factory); + + // --- Basic test ----------------------------------------------------------------------------------------------- // + @Test + public void testJdk170BasicDoSomethingWithString() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Basic", "doSomethingWithString")); + } + + + // --- Test 'if' and 'if-else' ---------------------------------------------------------------------------------- // + @Test + public void testJdk170If() throws Exception { + checkIfReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "if_"))); + } + + @Test + public void testJdk170IfIf() throws Exception { + ControlFlowGraph cfg = checkIfReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifIf"))); + + BasicBlock ifBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifBB.getType(), TYPE_IF); + assertEquals(ifBB.getSub1().getType(), TYPE_IF); + } + + @Test + public void testJdk170MethodCallInIfCondition() throws Exception { + checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "methodCallInIfCondition"))); + } + + @Test + public void testJdk170IlElse() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElse"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + assertEquals(ifElseBB.getCondition().getType(), TYPE_CONDITION); + assertTrue(ifElseBB.getCondition().mustInverseCondition()); + } + + @Test + public void testJdk170IlElseIfElse() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElseIfElse"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getSub2().getType(), TYPE_IF_ELSE); + } + + @Test + public void testJdk170IfORCondition() throws Exception { + ControlFlowGraph cfg = checkIfReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifORCondition"))); + BasicBlock ifBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifBB.getCondition().getType(), TYPE_CONDITION_OR); + assertEquals(ifBB.getCondition().getSub1().getType(), TYPE_CONDITION); + assertFalse(ifBB.getCondition().getSub1().mustInverseCondition()); + assertEquals(ifBB.getCondition().getSub2().getType(), TYPE_CONDITION_OR); + assertEquals(ifBB.getCondition().getSub2().getSub1().getType(), TYPE_CONDITION); + assertFalse(ifBB.getCondition().getSub2().getSub1().mustInverseCondition()); + assertEquals(ifBB.getCondition().getSub2().getSub2().getType(), TYPE_CONDITION); + assertTrue(ifBB.getCondition().getSub2().getSub2().mustInverseCondition()); + } + + @Test + public void testJdk170IfANDCondition() throws Exception { + ControlFlowGraph cfg = checkIfReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifANDCondition"))); + BasicBlock ifBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifBB.getCondition().getType(), TYPE_CONDITION_AND); + assertEquals(ifBB.getCondition().getSub1().getType(), TYPE_CONDITION); + assertTrue(ifBB.getCondition().getSub1().mustInverseCondition()); + assertEquals(ifBB.getCondition().getSub2().getType(), TYPE_CONDITION_AND); + assertEquals(ifBB.getCondition().getSub2().getSub1().getType(), TYPE_CONDITION); + assertTrue(ifBB.getCondition().getSub2().getSub1().mustInverseCondition()); + assertEquals(ifBB.getCondition().getSub2().getSub2().getType(), TYPE_CONDITION); + assertTrue(ifBB.getCondition().getSub2().getSub2().mustInverseCondition()); + } + + @Test + public void testJdk170IfElseORCondition() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElseORCondition"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getCondition().getType(), TYPE_CONDITION_OR); + assertEquals(ifElseBB.getCondition().getSub1().getType(), TYPE_CONDITION); + assertFalse(ifElseBB.getCondition().getSub1().mustInverseCondition()); + assertEquals(ifElseBB.getCondition().getSub2().getType(), TYPE_CONDITION_OR); + } + + @Test + public void testJdk170IfElseANDCondition() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElseANDCondition"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getCondition().getType(), TYPE_CONDITION_AND); + assertEquals(ifElseBB.getCondition().getSub1().getType(), TYPE_CONDITION); + assertTrue(ifElseBB.getCondition().getSub1().mustInverseCondition()); + assertEquals(ifElseBB.getCondition().getSub2().getType(), TYPE_CONDITION_AND); + } + + @Test + public void testJdk170IfElse6ANDAnd2ORCondition() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElse6ANDAnd2ORCondition"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getCondition().getType(), TYPE_CONDITION_OR); + assertEquals(ifElseBB.getCondition().getSub1().getType(), TYPE_CONDITION_AND); + assertEquals(ifElseBB.getCondition().getSub2().getType(), TYPE_CONDITION_OR); + } + + @Test + public void testJdk170IfElse6ORAnd2ANDCondition() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElse6ORAnd2ANDCondition"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getCondition().getType(), TYPE_CONDITION_AND); + assertEquals(ifElseBB.getCondition().getSub1().getType(), TYPE_CONDITION_OR); + assertEquals(ifElseBB.getCondition().getSub2().getType(), TYPE_CONDITION_AND); + } + + @Test + public void testJdk170IfElseORAndANDConditions() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElseORAndANDConditions"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + assertEquals(ifElseBB.getCondition().getType(), TYPE_CONDITION_AND); + assertEquals(ifElseBB.getCondition().getSub1().getType(), TYPE_CONDITION_OR); + assertEquals(ifElseBB.getCondition().getSub2().getType(), TYPE_CONDITION_AND); + } + + @Test + public void testIfElseANDAndORConditions() throws Exception { + ControlFlowGraph cfg = checkIfElseReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/IfElse", "ifElseANDAndORConditions"))); + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + assertEquals(ifElseBB.getCondition().getType(), TYPE_CONDITION_OR); + assertEquals(ifElseBB.getCondition().getSub1().getType(), TYPE_CONDITION_AND); + assertEquals(ifElseBB.getCondition().getSub2().getType(), TYPE_CONDITION_OR); + } + + protected static ControlFlowGraph checkIfReduction(ControlFlowGraph cfg) throws Exception { + BasicBlock ifBB = checkIfCommonReduction(cfg); + + assertEquals(ifBB.getType(), TYPE_IF); + + return cfg; + } + + protected static ControlFlowGraph checkIfElseReduction(ControlFlowGraph cfg) throws Exception { + BasicBlock ifElseBB = checkIfCommonReduction(cfg); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + assertNotNull(ifElseBB.getSub2()); + assertEquals(ifElseBB.getSub2().getNext(), END); + + return cfg; + } + + protected static BasicBlock checkIfCommonReduction(ControlFlowGraph cfg) throws Exception { + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + assertEquals(startBB.getType(), TYPE_START); + + assertNotNull(startBB.getNext()); + + BasicBlock ifBB = startBB.getNext().getNext(); + + assertNotNull(ifBB.getCondition()); + assertNotNull(ifBB.getSub1()); + assertEquals(ifBB.getSub1().getNext(), END); + assertNotNull(ifBB.getNext()); + + return ifBB; + } + + + // --- Test outer & inner classes ------------------------------------------------------------------------------- // + @Test + public void testJdk170OuterClass() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/OuterClass", "")); + } + + + // --- Test ternary operator ------------------------------------------------------------------------------------ // + @Test + public void testJdk170TernaryOperatorsInTernaryOperator() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorsInTernaryOperator")); + } + + @Test + public void testJdk118TernaryOperatorsInReturn() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorsInReturn")); + } + + @Test + public void testJdk170TernaryOperatorsInReturn() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorsInReturn")); + } + + @Test + public void testJdk118TernaryOperatorInIf1() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIf1")); + + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getType(), TYPE_IF); + assertEquals(ifElseBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(ifElseBB.getNext().getNext().getType(), TYPE_RETURN); + + BasicBlock conditionTernaryOperatorBB = ifElseBB.getCondition(); + + assertEquals(conditionTernaryOperatorBB.getType(), TYPE_CONDITION_TERNARY_OPERATOR); + assertEquals(conditionTernaryOperatorBB.getCondition().getType(), TYPE_CONDITION); + assertTrue(conditionTernaryOperatorBB.getCondition().mustInverseCondition()); + assertEquals(conditionTernaryOperatorBB.getSub1().getType(), TYPE_GOTO_IN_TERNARY_OPERATOR); + assertEquals(conditionTernaryOperatorBB.getSub2().getType(), TYPE_STATEMENTS); + } + + @Test + public void testJdk170TernaryOperatorInIf1() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIf1")); + } + + @Test + public void testJdk118TernaryOperatorInIfElse1() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse1")); + } + + @Test + public void testJdk170TernaryOperatorInIfElse1() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse1")); + } + + @Test + public void testJdk118TernaryOperatorInIfElse2() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse2")); + } + + @Test + public void testJdk170TernaryOperatorInIfElse2() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse2")); + } + + @Test + public void testJdk118TernaryOperatorInIfElse3() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse3")); + + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + assertEquals(ifElseBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(ifElseBB.getNext().getNext().getType(), TYPE_RETURN); + + BasicBlock conditionAndBB = ifElseBB.getCondition(); + + assertEquals(conditionAndBB.getType(), TYPE_CONDITION_AND); + assertEquals(conditionAndBB.getSub1().getType(), TYPE_CONDITION); + assertTrue(conditionAndBB.getSub1().mustInverseCondition()); + assertEquals(conditionAndBB.getSub2().getType(), TYPE_CONDITION); + assertFalse(conditionAndBB.getSub2().mustInverseCondition()); + } + + @Test + public void testJdk170TernaryOperatorInIfElse3() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse3")); + } + + @Test + public void testJdk118TernaryOperatorInIfElse4() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse4")); + } + + @Test + public void testJdk118TernaryOperatorInIfElse5() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse5")); + } + + @Test + public void testJdk118TernaryOperatorInIfElse6() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElse6")); + } + + @Test + public void testJdk118TernaryOperatorInIfElseFalse() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElseFalse")); + } + + @Test + public void testJdk170TernaryOperatorInIfElseFalse() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElseFalse")); + } + + @Test + public void testJdk118TernaryOperatorInIfElseANDCondition() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElseANDCondition")); + } + + @Test + public void testJdk170TernaryOperatorInIfElseANDCondition() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElseANDCondition")); + } + + @Test + public void testJdk118TernaryOperatorInIfElseORCondition() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElseORCondition")); + + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + assertEquals(ifElseBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(ifElseBB.getNext().getNext().getType(), TYPE_RETURN); + + BasicBlock conditionOrBB = ifElseBB.getCondition(); + + assertEquals(conditionOrBB.getType(), TYPE_CONDITION_OR); + assertEquals(conditionOrBB.getSub2().getType(), TYPE_CONDITION); + assertTrue(conditionOrBB.getSub2().mustInverseCondition()); + + BasicBlock conditionOrBB2 = conditionOrBB.getSub1(); + + assertEquals(conditionOrBB2.getType(), TYPE_CONDITION_OR); + assertEquals(conditionOrBB2.getSub1().getType(), TYPE_CONDITION); + assertFalse(conditionOrBB2.getSub1().mustInverseCondition()); + + BasicBlock conditionTernaryOperatorBB = conditionOrBB2.getSub2(); + + assertEquals(conditionTernaryOperatorBB.getType(), TYPE_CONDITION_TERNARY_OPERATOR); + assertEquals(conditionTernaryOperatorBB.getCondition().getType(), TYPE_CONDITION); + assertTrue(conditionTernaryOperatorBB.getCondition().mustInverseCondition()); + assertEquals(conditionTernaryOperatorBB.getSub1().getType(), TYPE_GOTO_IN_TERNARY_OPERATOR); + assertEquals(conditionTernaryOperatorBB.getSub2().getType(), TYPE_STATEMENTS); + } + + @Test + public void testJdk170TernaryOperatorInIfElseORCondition() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TernaryOperator", "ternaryOperatorInIfElseORCondition")); + + BasicBlock ifElseBB = cfg.getStart().getNext().getNext(); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + assertEquals(ifElseBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(ifElseBB.getNext().getNext().getType(), TYPE_RETURN); + + BasicBlock conditionOrBB = ifElseBB.getCondition(); + + assertEquals(conditionOrBB.getType(), TYPE_CONDITION_OR); + assertEquals(conditionOrBB.getSub2().getType(), TYPE_CONDITION); + assertTrue(conditionOrBB.getSub2().mustInverseCondition()); + + BasicBlock conditionOrBB2 = conditionOrBB.getSub1(); + + assertEquals(conditionOrBB2.getType(), TYPE_CONDITION_OR); + assertEquals(conditionOrBB2.getSub1().getType(), TYPE_CONDITION); + assertFalse(conditionOrBB2.getSub1().mustInverseCondition()); + + BasicBlock conditionTernaryOperatorBB = conditionOrBB2.getSub2(); + + assertEquals(conditionTernaryOperatorBB.getType(), TYPE_CONDITION_TERNARY_OPERATOR); + assertEquals(conditionTernaryOperatorBB.getCondition().getType(), TYPE_CONDITION); + assertTrue(conditionTernaryOperatorBB.getCondition().mustInverseCondition()); + assertEquals(conditionTernaryOperatorBB.getSub1().getType(), TYPE_CONDITION); + assertTrue(conditionTernaryOperatorBB.getSub1().mustInverseCondition()); + assertEquals(conditionTernaryOperatorBB.getSub2().getType(), TYPE_CONDITION); + assertFalse(conditionTernaryOperatorBB.getSub2().mustInverseCondition()); + } + + + // --- Test 'switch' -------------------------------------------------------------------------------------------- // + @Test + public void testJdk170SimpleSwitch() throws Exception { + checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "simpleSwitch"))); + } + + @Test + public void testJdk170SwitchFirstBreakMissing() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchFirstBreakMissing"))); + SwitchCase sc0 = switchBB.getSwitchCases().get(0); + + assertFalse(sc0.isDefaultCase()); + assertEquals(sc0.getValue(), 0); + assertEquals(sc0.getBasicBlock().getNext(), END); + + SwitchCase sc1 = switchBB.getSwitchCases().get(1); + + assertFalse(sc1.isDefaultCase()); + assertEquals(sc1.getValue(), 1); + assertEquals(sc0.getBasicBlock().getNext(), SWITCH_BREAK); + } + + @Test + public void testJdk170SwitchSecondBreakMissing() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchSecondBreakMissing"))); + SwitchCase sc0 = switchBB.getSwitchCases().get(0); + + assertTrue(sc0.isDefaultCase()); + + SwitchCase sc1 = switchBB.getSwitchCases().get(1); + + assertFalse(sc1.isDefaultCase()); + assertEquals(sc1.getValue(), 0); + assertEquals(sc1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc1.getBasicBlock().getNext().getType(), TYPE_SWITCH_BREAK); + + SwitchCase sc2 = switchBB.getSwitchCases().get(2); + + assertFalse(sc2.isDefaultCase()); + assertEquals(sc2.getValue(), 1); + assertEquals(sc2.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc2.getBasicBlock().getNext().getType(), TYPE_END); + } + + @Test + public void testJdk170SwitchDefault() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchDefault"))); + SwitchCase scDefault = switchBB.getSwitchCases().get(0); + + assertTrue(scDefault.isDefaultCase()); + + SwitchCase sc1 = switchBB.getSwitchCases().get(1); + + assertFalse(sc1.isDefaultCase()); + assertEquals(sc1.getValue(), 0); + assertEquals(sc1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc1.getBasicBlock().getNext().getType(), TYPE_END); + + SwitchCase sc2 = switchBB.getSwitchCases().get(2); + + assertFalse(sc2.isDefaultCase()); + assertEquals(sc2.getValue(), 1); + assertEquals(sc2.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc2.getBasicBlock().getNext().getType(), TYPE_SWITCH_BREAK); + } + + @Test + public void testJdk170LookupSwitchDefault() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "lookupSwitchDefault"))); + SwitchCase scDefault = switchBB.getSwitchCases().get(0); + + assertTrue(scDefault.isDefaultCase()); + assertEquals(scDefault.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(scDefault.getBasicBlock().getNext().getType(), TYPE_SWITCH_BREAK); + + SwitchCase sc1 = switchBB.getSwitchCases().get(1); + + assertFalse(sc1.isDefaultCase()); + assertEquals(sc1.getValue(), 0); + assertEquals(sc1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc1.getBasicBlock().getNext().getType(), TYPE_END); + + SwitchCase sc2 = switchBB.getSwitchCases().get(2); + + assertFalse(sc2.isDefaultCase()); + assertEquals(sc2.getValue(), 1); + assertEquals(sc2.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc2.getBasicBlock().getNext().getType(), TYPE_SWITCH_BREAK); + } + + @Test + public void testJdk170SwitchOneExitInFirstCase() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchOneExitInFirstCase"))); + SwitchCase scDefault = switchBB.getSwitchCases().get(0); + + assertTrue(scDefault.isDefaultCase()); + assertEquals(scDefault.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(scDefault.getBasicBlock().getNext().getType(), TYPE_RETURN); + + SwitchCase sc2 = switchBB.getSwitchCases().get(2); + + assertFalse(sc2.isDefaultCase()); + assertEquals(sc2.getValue(), 1); + assertEquals(sc2.getBasicBlock().getType(), TYPE_THROW); + } + + @Test + public void testJdk170SwitchOneExitInSecondCase() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchOneExitInSecondCase"))); + SwitchCase scDefault = switchBB.getSwitchCases().get(0); + + assertTrue(scDefault.isDefaultCase()); + assertEquals(scDefault.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(scDefault.getBasicBlock().getNext().getType(), TYPE_RETURN); + + SwitchCase sc1 = switchBB.getSwitchCases().get(1); + + assertFalse(sc1.isDefaultCase()); + assertEquals(sc1.getValue(), 0); + assertEquals(sc1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc1.getBasicBlock().getNext().getType(), TYPE_RETURN); + } + + @Test + public void testJdk170SwitchOneExitInLastCase() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchOneExitInLastCase"))); + SwitchCase sc0 = switchBB.getSwitchCases().get(0); + + assertFalse(sc0.isDefaultCase()); + assertEquals(sc0.getValue(), 0); + assertEquals(sc0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc0.getBasicBlock().getNext().getType(), TYPE_RETURN); + + SwitchCase sc1 = switchBB.getSwitchCases().get(1); + + assertFalse(sc1.isDefaultCase()); + assertEquals(sc1.getValue(), 1); + assertEquals(sc1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(sc1.getBasicBlock().getNext().getType(), TYPE_RETURN); + } + + @Test + public void testJdk170ComplexSwitch() throws Exception { + BasicBlock switchBB = checkSwitchReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "complexSwitch"))); + SwitchCase scDefault = switchBB.getSwitchCases().get(0); + + assertTrue(scDefault.isDefaultCase()); + + SwitchCase sc1 = switchBB.getSwitchCases().get(1); + + assertFalse(sc1.isDefaultCase()); + assertEquals(sc1.getValue(), 1); + + SwitchCase sc2 = switchBB.getSwitchCases().get(2); + + assertFalse(sc2.isDefaultCase()); + assertEquals(sc2.getValue(), 2); + } + + @Test + public void testJdk170SwitchOnLastPosition() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchOnLastPosition")); + } + + @Test + public void testJdk170SwitchFirstIfBreakMissing() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/Switch", "switchFirstIfBreakMissing")); + } + + @Test + public void testJdk170SwitchString() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/AdvancedSwitch", "switchString")); + } + + protected static BasicBlock checkSwitchReduction(ControlFlowGraph cfg) throws Exception { + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock switchBB = startBB.getNext(); + + assertNotNull(switchBB); + assertEquals(switchBB.getType(), TYPE_SWITCH); + + BasicBlock next = switchBB.getNext(); + assertNotNull(next); + assertEquals(next.getType(), TYPE_STATEMENTS); + + assertNotNull(next.getNext()); + assertEquals(next.getNext().getType(), TYPE_RETURN); + + return switchBB; + } + + + // --- Test 'while' --------------------------------------------------------------------------------------------- // + @Test + public void testJdk170SimpleWhile() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "simpleWhile")); + } + + @Test + public void testJdk170WhileIfContinue() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileIfContinue")); + } + + @Test + public void testJdk170WhileIfBreak() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileIfBreak")); + } + + @Test + public void testJdk170WhileWhile() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileWhile")); + } + + @Test + public void testJdk170WhileThrow() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileThrow")); + } + + @Test + public void testJdk170WhileTrue() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileTrue")); + } + + @Test + public void testJdk170WhileTryFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileTryFinally")); + } + + @Test + public void testJdk170TryWhileFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "tryWhileFinally")); + } + + @Test + public void testJdk170InfiniteWhileTryFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "infiniteWhileTryFinally")); + } + + @Test + public void testJdk170TryInfiniteWhileFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "tryInfiniteWhileFinally")); + } + + @Test + public void testJdk170WhileTrueIf() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileTrueIf")); + + BasicBlock mainLoopBB = cfg.getStart().getNext().getNext(); + + assertEquals(mainLoopBB.getType(), TYPE_LOOP); + + BasicBlock firstIfBB = mainLoopBB.getSub1().getNext(); + + assertEquals(firstIfBB.getType(), TYPE_IF); + + BasicBlock innerLoopBB = firstIfBB.getSub1().getNext(); + + assertEquals(innerLoopBB.getType(), TYPE_LOOP); + assertEquals(innerLoopBB.getNext().getType(), TYPE_LOOP_END); + + BasicBlock secondIfBB = firstIfBB.getNext(); + + assertEquals(secondIfBB.getSub1().getNext().getType(), TYPE_LOOP_START); + } + + @Test + public void testJdk170WhileContinueBreak() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "whileContinueBreak")); + } + + @Test + public void testJdk170TwoWiles() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/While", "twoWiles")); + + BasicBlock firstLoopBB = cfg.getStart().getNext().getNext(); + + assertEquals(firstLoopBB.getType(), TYPE_LOOP); + + BasicBlock nextLoopBB = firstLoopBB.getNext(); + + assertEquals(nextLoopBB.getType(), TYPE_LOOP); + + BasicBlock stmtBB = nextLoopBB.getNext(); + + assertEquals(stmtBB.getType(), TYPE_STATEMENTS); + + BasicBlock returnBB = stmtBB.getNext(); + + assertEquals(returnBB.getType(), TYPE_RETURN); + } + + // --- Test 'do-while' ------------------------------------------------------------------------------------------ // + @Test + public void testJdk170DoWhileWhile() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/DoWhile", "doWhileWhile")); + } + + @Test + public void testJdk170DoWhileTestPreInc() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/DoWhile", "doWhileTestPreInc")); + } + + @Test + public void testJdk170DoWhileTryFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/DoWhile", "doWhileTryFinally")); + } + + @Test + public void testJdk170TryDoWhileFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/DoWhile", "tryDoWhileFinally")); + } + + // --- Test 'for' ----------------------------------------------------------------------------------------------- // + @Test + public void testJdk150ForTryReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.5.0.zip"), "org/jd/core/test/For", "forTryReturn")); + BasicBlock loopBB = cfg.getStart().getNext().getNext(); + + assertEquals(loopBB.getType(), TYPE_LOOP); + assertEquals(loopBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(loopBB.getNext().getNext().getType(), TYPE_RETURN); + + BasicBlock bb = loopBB.getSub1(); + + assertEquals(bb.getType(), TYPE_IF); + assertEquals(bb.getNext().getType(), TYPE_LOOP_END); + + bb = bb.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_TRY); + assertEquals(bb.getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getNext().getNext().getType(), TYPE_LOOP_START); + } + + @Test + public void testJdk170IfForIfReturn() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/For", "ifForIfReturn")); + } + + @Test + public void testJdk170ForIfContinue() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/For", "forIfContinue")); + } + + @Test + public void testJdk170ForIfIfContinue() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/For", "forIfIfContinue")); + } + + @Test + public void testJdk170ForMultipleVariables2() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/For", "forMultipleVariables2")); + } + + + // --- Test 'break' and 'continue' ------------------------------------------------------------------------------ // + @Test + public void testJdk170DoWhileContinue() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/BreakContinue", "doWhileContinue")); + + BasicBlock mainLoopBB = cfg.getStart().getNext().getNext(); + + assertEquals(mainLoopBB.getType(), TYPE_LOOP); + + BasicBlock sub1 = mainLoopBB.getSub1(); + + assertEquals(sub1.getType(), TYPE_STATEMENTS); + assertEquals(sub1.getNext().getType(), TYPE_IF); + assertEquals(sub1.getNext().getSub1().getType(), TYPE_IF); + assertEquals(sub1.getNext().getNext().getType(), TYPE_IF); + assertEquals(sub1.getNext().getNext().getNext().getType(), TYPE_LOOP_START); + } + + @Test + public void testJdk170TripleDoWhile1() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/BreakContinue", "tripleDoWhile1")); + } + + @Test + public void testJdk170TripleDoWhile2() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/BreakContinue", "tripleDoWhile2")); + + BasicBlock mainLoopBB = cfg.getStart().getNext().getNext(); + + assertEquals(mainLoopBB.getType(), TYPE_LOOP); + + BasicBlock innerLoopBB = mainLoopBB.getSub1(); + + assertEquals(innerLoopBB.getType(), TYPE_LOOP); + assertEquals(innerLoopBB.getNext().getType(), TYPE_IF); + assertEquals(innerLoopBB.getNext().getNext().getType(), TYPE_LOOP_START); + assertEquals(innerLoopBB.getNext().getSub1().getType(), TYPE_LOOP_END); + + BasicBlock innerInnerLoopBB = innerLoopBB.getSub1(); + + assertEquals(innerInnerLoopBB.getType(), TYPE_LOOP); + assertEquals(innerInnerLoopBB.getNext().getType(), TYPE_IF); + assertEquals(innerInnerLoopBB.getNext().getNext().getType(), TYPE_LOOP_START); + assertEquals(innerInnerLoopBB.getNext().getSub1().getType(), TYPE_LOOP_END); + + BasicBlock bb = innerInnerLoopBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_IF); + assertEquals(bb.getNext().getNext().getType(), TYPE_IF); + assertEquals(bb.getNext().getNext().getSub1().getType(), TYPE_JUMP); + assertEquals(bb.getNext().getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getNext().getNext().getNext().getType(), TYPE_IF); + assertEquals(bb.getNext().getNext().getNext().getNext().getNext().getType(), TYPE_LOOP_START); + assertEquals(bb.getNext().getNext().getNext().getNext().getSub1().getType(), TYPE_LOOP_END); + } + + @Test + public void testJdk170DoWhileWhileIf() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/BreakContinue", "doWhileWhileIf")); + } + + @Test + public void testJdk170DoWhileWhileTryBreak() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/BreakContinue", "doWhileWhileTryBreak")); + + BasicBlock mainLoopBB = cfg.getStart().getNext().getNext(); + + assertEquals(mainLoopBB.getType(), TYPE_LOOP); + + BasicBlock innerLoopBB = mainLoopBB.getSub1(); + + assertEquals(innerLoopBB.getType(), TYPE_LOOP); + assertEquals(innerLoopBB.getSub1().getType(), TYPE_IF); + assertEquals(innerLoopBB.getSub1().getSub1().getType(), TYPE_TRY); + assertEquals(innerLoopBB.getSub1().getSub1().getSub1().getType(), TYPE_IF); + assertEquals(innerLoopBB.getSub1().getSub1().getSub1().getNext().getType(), TYPE_JUMP); + } + + + // --- Test 'try-catch-finally' --------------------------------------------------------------------------------- // + @Test + public void testJdk170MethodTryCatch() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatch")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_IF); + assertEquals(bb.getNext().getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_END); + + BasicBlock nextSimpleBB = tryBB.getNext(); + + assertNotNull(nextSimpleBB); + assertEquals(nextSimpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock returnBB = nextSimpleBB.getNext(); + + assertNotNull(returnBB); + assertEquals(returnBB.getType(), TYPE_RETURN); + } + + @Test + public void testEclipseJavaCompiler370MethodTrySwitchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTrySwitchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_SWITCH); + assertEquals(bb.getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextSimpleBB = tryBB.getNext(); + + assertNotNull(nextSimpleBB); + assertEquals(nextSimpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock returnBB = nextSimpleBB.getNext(); + + assertNotNull(returnBB); + assertEquals(returnBB.getType(), TYPE_RETURN); + } + + @Test + public void testEclipseJavaCompiler3130MethodTrySwitchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTrySwitchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_SWITCH); + assertEquals(bb.getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextSimpleBB = tryBB.getNext(); + + assertNotNull(nextSimpleBB); + assertEquals(nextSimpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock returnBB = nextSimpleBB.getNext(); + + assertNotNull(returnBB); + assertEquals(returnBB.getType(), TYPE_RETURN); + } + + @Test + public void testJdk170MethodTryCatchCatch() throws Exception { + BasicBlock tryBB = checkTryCatchFinallyReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchCatch"))); + + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock next = tryBB.getNext(); + + assertEquals(next.getType(), TYPE_STATEMENTS); + assertEquals(next.getNext().getType(), TYPE_RETURN); + } + + @Test + public void testEclipseJavaCompiler321MethodTryCatchCatch() throws Exception { + BasicBlock tryBB = checkTryCatchFinallyReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.2.1.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchCatch"))); + + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock next = tryBB.getNext(); + + assertEquals(next.getType(), TYPE_STATEMENTS); + assertEquals(next.getNext().getType(), TYPE_RETURN); + } + + @Test + public void testEclipseJavaCompiler321MethodTryCatchFinally1() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.2.1.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally1")); + } + + @Test + public void testJdk170MethodTryCatchCatchExitInTry() throws Exception { + BasicBlock tryBB = checkTryCatchFinallyReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchCatchOneExitInTry"))); + + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertEquals(eh1.getInternalThrowableName(), "java/lang/Exception"); + assertEquals(eh1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh1.getBasicBlock().getNext().getType(), TYPE_RETURN); + + BasicBlock next = tryBB.getNext(); + + assertEquals(next.getType(), TYPE_STATEMENTS); + assertEquals(next.getNext().getType(), TYPE_RETURN); + } + + @Test + public void testJdk170MethodTryCatchCatchExitInFirstCatch() throws Exception { + BasicBlock tryBB = checkTryCatchFinallyReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchCatchOneExitInFirstCatch"))); + + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_END); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertEquals(eh1.getInternalThrowableName(), "java/lang/Exception"); + assertEquals(eh1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh1.getBasicBlock().getNext().getType(), TYPE_RETURN); + + BasicBlock next = tryBB.getNext(); + + assertEquals(next.getType(), TYPE_STATEMENTS); + assertEquals(next.getNext().getType(), TYPE_RETURN); + } + + @Test + public void testJdk170MethodTryCatchCatchExitInLastCatch() throws Exception { + BasicBlock tryBB = checkTryCatchFinallyReduction(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchCatchOneExitInLastCatch"))); + + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertEquals(eh1.getInternalThrowableName(), "java/lang/Exception"); + assertEquals(eh1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh1.getBasicBlock().getNext().getType(), TYPE_RETURN); + + BasicBlock next = tryBB.getNext(); + + assertEquals(next.getType(), TYPE_END); + } + + @Test + public void testJdk170MethodTrySwitchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTrySwitchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_SWITCH); + assertEquals(bb.getNext().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextSimpleBB = tryBB.getNext(); + + assertNotNull(nextSimpleBB); + assertEquals(nextSimpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock returnBB = nextSimpleBB.getNext(); + + assertNotNull(returnBB); + assertEquals(returnBB.getType(), TYPE_RETURN); + } + + @Test + public void testJdk131MethodTryCatchFinallyInTryCatchFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.3.1.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinallyInTryCatchFinally")); + } + + @Test + public void testJdk170MethodTryCatchFinallyInTryCatchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinallyInTryCatchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_TRY); + assertEquals(bb.getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getNext().getNext().getType(), TYPE_TRY); + assertEquals(bb.getNext().getNext().getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getNext().getNext().getNext().getNext().getType(), TYPE_LOOP); + assertEquals(bb.getNext().getNext().getNext().getNext().getNext().getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_LOOP); + assertEquals(eh0.getBasicBlock().getNext().getNext().getType(), TYPE_THROW); + + BasicBlock returnBB = tryBB.getNext(); + + assertNotNull(returnBB); + assertEquals(returnBB.getType(), TYPE_RETURN_VALUE); + } + + protected static BasicBlock checkTryCatchFinallyReduction(ControlFlowGraph cfg) throws Exception { + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertNotNull(simpleBB); + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertNotNull(tryBB.getSub1()); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + for (ExceptionHandler exceptionHandler : tryBB.getExceptionHandlers()) { + assertNotNull(exceptionHandler.getInternalThrowableName()); + assertNotNull(exceptionHandler.getBasicBlock()); + } + + return tryBB; + } + + + // --- Test 'try-with-resources' --------------------------------------------------------------------------------- // + @Test + public void testJdk170Try1Resource() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryWithResources", "try1Resource")); + } + + @Test + public void testJdk170TryCatch1Resource() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryWithResources", "tryCatch1Resource")); + } + + @Test + public void testJdk170TryFinally1Resource() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryWithResources", "tryFinally1Resource")); + } + + @Test + public void testJdk170TryCatchFinally1Resource() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryWithResources", "tryCatchFinally1Resource")); + } + + @Test + public void testJdk170TryCatchFinally2Resources() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryWithResources", "tryCatchFinally2Resources")); + } + + @Test + public void testJdk170TryCatchFinally4Resources() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryWithResources", "tryCatchFinally4Resources")); + } + + + // --- methodTryFinallyReturn --- // + @Test + public void testJdk170MethodTryFinallyReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler370MethodTryFinallyReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryFinallyReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + + // --- methodTryCatch3 --- // + @Test + public void testJdk170MethodTryCatch3() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatch3")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_RETURN_VALUE); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler370MethodTryCatch3() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatch3")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_RETURN_VALUE); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryCatch3() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatch3")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_RETURN_VALUE); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + + // --- methodTryFinally1 --- // + @Test + public void testJdk170MethodTryFinally1() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinally1")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextSimpleBB = tryBB.getNext(); + assertNotNull(nextSimpleBB); + assertEquals(nextSimpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock returnBB = nextSimpleBB.getNext(); + + assertNotNull(returnBB); + assertEquals(returnBB.getType(), TYPE_RETURN); + } + + + // --- methodTryFinally3 --- // + @Test + public void testJdk170MethodTryFinally3() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinally3")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_THROW); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler370MethodTryFinally3() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinally3")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_THROW); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryFinally3() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinally3")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_THROW); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + + // --- methodTryFinally4 --- // + @Test + public void testJdk170MethodTryFinally4() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinally4")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_IF); + assertEquals(bb.getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getNext().getNext().getType(), TYPE_END); + assertEquals(bb.getNext().getSub1().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getSub1().getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_STATEMENTS); + assertEquals(nextBB.getNext().getType(), TYPE_RETURN); + } + + @Test + public void testEclipseJavaCompiler370MethodTryFinally4() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinally4")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_IF); + assertEquals(bb.getNext().getNext().getType(), TYPE_END); + assertEquals(bb.getNext().getSub1().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getSub1().getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_STATEMENTS); + assertEquals(nextBB.getNext().getType(), TYPE_RETURN); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryFinally4() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryFinally4")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getType(), TYPE_IF); + assertEquals(bb.getNext().getNext().getType(), TYPE_END); + assertEquals(bb.getNext().getSub1().getType(), TYPE_STATEMENTS); + assertEquals(bb.getNext().getSub1().getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_STATEMENTS); + assertEquals(nextBB.getNext().getType(), TYPE_RETURN); + } + + + // --- methodTryCatchFinally2 --- // + @Test + public void testJdk170MethodTryCatchFinally2() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally2")); + } + + @Test + public void testEclipseJavaCompiler370MethodTryCatchFinally2() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally2")); + BasicBlock tryBB = cfg.getStart().getNext().getNext(); + + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertEquals(tryBB.getSub1().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getSub1().getNext().getType(), TYPE_END); + assertEquals(tryBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getNext().getNext().getNext().getType(), TYPE_RETURN); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryCatchFinally2() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally2")); + BasicBlock tryBB = cfg.getStart().getNext().getNext(); + + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertEquals(tryBB.getSub1().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getSub1().getNext().getType(), TYPE_END); + assertEquals(tryBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getNext().getNext().getNext().getType(), TYPE_RETURN); + } + + + // --- methodTryCatchFinally4 --- // + @Test + public void testJdk170MethodTryCatchFinally4() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally4")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_THROW); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/Exception"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_END); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertNull(eh1.getInternalThrowableName()); + assertEquals(eh1.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock returnBB = tryBB.getNext(); + + assertNotNull(returnBB); + assertEquals(returnBB.getType(), TYPE_RETURN_VALUE); + } + + + // --- methodTryCatchFinally5 --- // + @Test + public void testEclipseJavaCompiler321MethodTryCatchFinally5() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.2.1.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally5")); + } + + @Test + public void testEclipseJavaCompiler370MethodTryCatchFinally5() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally5")); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryCatchFinally5() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally5")); + } + + @Test + public void testJdk170MethodTryCatchFinally5() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinally5")); + } + + // --- methodTryTryReturnFinally*Finally --- // + @Test + public void testJdk170MethodTryTryReturnFinallyFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryReturnFinallyFinally")); + } + + @Test + public void testEclipseJavaCompiler321MethodTryTryReturnFinallyCatchFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.2.1.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryReturnFinallyCatchFinally")); + } + + @Test + public void testJdk170MethodTryTryReturnFinallyCatchFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryReturnFinallyCatchFinally")); + } + + + // --- methodTryTryFinallyFinallyTryFinallyReturn --- // + @Test + public void testEclipseJavaCompiler370MethodTryTryFinallyFinallyTryFinallyReturn() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinallyReturn")); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryTryFinallyFinallyTryFinallyReturn() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinallyReturn")); + } + + @Test + public void testJdk170MethodTryTryFinallyFinallyTryFinallyReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_TRY); + assertEquals(bb.getNext().getType(), TYPE_TRY); + assertEquals(bb.getNext().getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_TRY); + assertEquals(eh0.getBasicBlock().getNext().getNext().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_STATEMENTS); + assertEquals(nextBB.getNext().getType(), TYPE_RETURN); + } + + + // --- complexMethodTryCatchCatchFinally --- // + @Test + public void testJdk170MethodTryTryFinallyFinallyTryFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK5(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testEclipseJavaCompiler321ComplexMethodTryCatchCatchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.2.1.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + } + + @Test + public void testEclipseJavaCompiler370ComplexMethodTryCatchCatchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + } + + @Test + public void testEclipseJavaCompiler3130ComplexMethodTryCatchCatchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + } + + @Test + public void testHarmonyJdkR533500ComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK118(checkCFGReduction(searchMethod(getResource("zip/data-java-harmony-jdk-r533500.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testIbm_J9_VmComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK5(checkCFGReduction(searchMethod(getResource("zip/data-java-ibm-j9_vm.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testJdk118ComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK118(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testJdk131ComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK118(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.3.1.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testJdk142ComplexMethodTryCatchCatchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.4.2.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_JSR); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 3); + + assertEquals(tryBB.getSub1().getType(), TYPE_TRY); + assertEquals(tryBB.getSub1().getNext().getType(), TYPE_END); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNotNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_TRY); + assertEquals(eh0.getBasicBlock().getNext().getNext().getType(), TYPE_END); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertNotNull(eh1.getInternalThrowableName()); + assertEquals(eh1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh1.getBasicBlock().getNext().getType(), TYPE_TRY); + assertEquals(eh1.getBasicBlock().getNext().getNext().getType(), TYPE_END); + + ExceptionHandler eh2 = tryBB.getExceptionHandlers().get(2); + + assertNull(eh2.getInternalThrowableName()); + assertEquals(eh2.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh2.getBasicBlock().getNext().getType(), TYPE_JSR); + assertEquals(eh2.getBasicBlock().getNext().getNext().getType(), TYPE_THROW); + assertEquals(eh2.getBasicBlock().getNext().getBranch().getType(), TYPE_STATEMENTS); + assertEquals(eh2.getBasicBlock().getNext().getBranch().getNext().getType(), TYPE_TRY); + assertEquals(eh2.getBasicBlock().getNext().getBranch().getNext().getNext().getType(), TYPE_RET); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_STATEMENTS); + assertEquals(nextBB.getNext().getType(), TYPE_RETURN); + } + + @Test + public void testJdk150ComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK5(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.5.0.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testJdk160ComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK5(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.6.0.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testJdk170ComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK5(checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testJikes1_22_1WindowsComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK118(checkCFGReduction(searchMethod(getResource("zip/data-java-jikes-1.22-1.windows.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + @Test + public void testJRockit90_150_06ComplexMethodTryCatchCatchFinally() throws Exception { + checkComplexMethodTryCatchCatchFinally_JDK5(checkCFGReduction(searchMethod(getResource("zip/data-java-jrockit-90_150_06.zip"), "org/jd/core/test/TryCatchFinally", "complexMethodTryCatchCatchFinally"))); + } + + protected void checkComplexMethodTryCatchCatchFinally_JDK5(ControlFlowGraph cfg) throws Exception { + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 3); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_TRY); + assertEquals(bb.getNext().getType(), TYPE_TRY); + assertEquals(bb.getNext().getNext().getType(), TYPE_END); + assertEquals(bb.getExceptionHandlers().size(), 3); + assertEquals(bb.getNext().getExceptionHandlers().size(), 3); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_TRY); + assertEquals(eh0.getBasicBlock().getNext().getNext().getType(), TYPE_TRY); + assertEquals(eh0.getBasicBlock().getNext().getNext().getNext().getType(), TYPE_END); + assertEquals(eh0.getBasicBlock().getNext().getExceptionHandlers().size(), 3); + assertEquals(eh0.getBasicBlock().getNext().getNext().getExceptionHandlers().size(), 3); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertEquals(eh1.getInternalThrowableName(), "java/lang/Exception"); + assertEquals(eh1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh1.getBasicBlock().getNext().getType(), TYPE_TRY); + assertEquals(eh1.getBasicBlock().getNext().getNext().getType(), TYPE_TRY); + assertEquals(eh1.getBasicBlock().getNext().getNext().getNext().getType(), TYPE_END); + assertEquals(eh1.getBasicBlock().getNext().getExceptionHandlers().size(), 3); + assertEquals(eh1.getBasicBlock().getNext().getNext().getExceptionHandlers().size(), 3); + + ExceptionHandler eh2 = tryBB.getExceptionHandlers().get(2); + + assertNull(eh2.getInternalThrowableName()); + assertEquals(eh2.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh2.getBasicBlock().getNext().getType(), TYPE_TRY); + assertEquals(eh2.getBasicBlock().getNext().getNext().getType(), TYPE_THROW); + assertEquals(eh2.getBasicBlock().getNext().getExceptionHandlers().size(), 3); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_STATEMENTS); + assertEquals(nextBB.getNext().getType(), TYPE_RETURN); + } + + protected void checkComplexMethodTryCatchCatchFinally_JDK118(ControlFlowGraph cfg) throws Exception { + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_JSR); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 3); + + BasicBlock sub1 = tryBB.getSub1(); + + assertEquals(sub1.getType(), TYPE_TRY_JSR); + assertEquals(sub1.getNext().getType(), TYPE_END); + assertEquals(sub1.getExceptionHandlers().size(), 3); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh0.getBasicBlock().getNext().getType(), TYPE_TRY_JSR); + assertEquals(eh0.getBasicBlock().getNext().getNext().getType(), TYPE_END); + assertEquals(eh0.getBasicBlock().getNext().getExceptionHandlers().size(), 3); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertEquals(eh1.getInternalThrowableName(), "java/lang/Exception"); + assertEquals(eh1.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh1.getBasicBlock().getNext().getType(), TYPE_TRY_JSR); + assertEquals(eh1.getBasicBlock().getNext().getNext().getType(), TYPE_END); + assertEquals(eh1.getBasicBlock().getNext().getExceptionHandlers().size(), 3); + + ExceptionHandler eh2 = tryBB.getExceptionHandlers().get(2); + + assertNull(eh2.getInternalThrowableName()); + assertEquals(eh2.getBasicBlock().getType(), TYPE_STATEMENTS); + assertEquals(eh2.getBasicBlock().getNext().getType(), TYPE_JSR); + assertEquals(eh2.getBasicBlock().getNext().getNext().getType(), TYPE_THROW); + assertEquals(eh2.getBasicBlock().getNext().getBranch().getType(), TYPE_STATEMENTS); + assertEquals(eh2.getBasicBlock().getNext().getBranch().getNext().getType(), TYPE_TRY_JSR); + assertEquals(eh2.getBasicBlock().getNext().getBranch().getNext().getExceptionHandlers().size(), 3); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_STATEMENTS); + assertEquals(nextBB.getNext().getType(), TYPE_RETURN); + } + + + // --- methodIfIfTryCatch --- // + @Test + public void testJdk118MethodIfIfTryCatch() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TryCatchFinally", "methodIfIfTryCatch")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock ifBB = startBB.getNext(); + + assertEquals(ifBB.getType(), TYPE_IF); + assertEquals(ifBB.getNext().getType(), TYPE_RETURN); + + BasicBlock ifElseBB = ifBB.getSub1(); + + assertEquals(ifElseBB.getType(), TYPE_IF_ELSE); + + assertEquals(ifElseBB.getSub1().getType(), TYPE_STATEMENTS); + assertEquals(ifElseBB.getSub1().getNext().getType(), TYPE_TRY); + assertEquals(ifElseBB.getSub1().getNext().getNext().getType(), TYPE_END); + + assertEquals(ifElseBB.getSub2().getType(), TYPE_STATEMENTS); + assertEquals(ifElseBB.getSub2().getNext().getType(), TYPE_END); + } + + + // --- methodTryCatchFinallyReturn --- // + @Test + public void testJdk170MethodTryCatchFinallyReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_RETURN_VALUE); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertNull(eh1.getInternalThrowableName()); + assertEquals(eh1.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler370MethodTryCatchFinallyReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertNull(eh1.getInternalThrowableName()); + assertEquals(eh1.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryCatchFinallyReturn() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 2); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_STATEMENTS); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertEquals(eh0.getInternalThrowableName(), "java/lang/RuntimeException"); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + + ExceptionHandler eh1 = tryBB.getExceptionHandlers().get(1); + + assertNull(eh1.getInternalThrowableName()); + assertEquals(eh1.getBasicBlock().getType(), TYPE_THROW); + + BasicBlock nextBB = tryBB.getNext(); + + assertNotNull(nextBB); + assertEquals(nextBB.getType(), TYPE_END); + } + + + // --- complexMethodTryFinallyReturn --- // + @Test + public void testJdk170MethodComplexTryCatchCatchFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinallyReturn")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + assertEquals(tryBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getNext().getNext().getType(), TYPE_RETURN); + + BasicBlock bb = tryBB.getSub1(); + + assertEquals(bb.getType(), TYPE_TRY); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + + BasicBlock subTryBB = tryBB.getSub1(); + + assertNotNull(subTryBB); + assertEquals(subTryBB.getType(), TYPE_TRY); + assertEquals(subTryBB.getNext().getType(), TYPE_TRY); + assertEquals(subTryBB.getNext().getNext().getType(), TYPE_END); + } + + @Test + public void testJdk170MethodTryCatchTryCatchThrow() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryCatchTryCatchThrow")); + } + + // --- methodTryTryFinallyFinallyTryFinally --- // + @Test + public void testEclipseJavaCompiler370MethodTryTryFinallyFinallyTryFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.7.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + assertEquals(tryBB.getNext().getType(), TYPE_TRY_ECLIPSE); + assertEquals(tryBB.getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getNext().getNext().getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + + BasicBlock subTryBB = tryBB.getSub1(); + + assertEquals(subTryBB.getType(), TYPE_TRY_ECLIPSE); + assertNotNull(subTryBB.getExceptionHandlers()); + assertEquals(subTryBB.getExceptionHandlers().size(), 1); + assertEquals(subTryBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(subTryBB.getNext().getNext().getType(), TYPE_END); + + eh0 = subTryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + } + + @Test + public void testEclipseJavaCompiler3130MethodTryTryFinallyFinallyTryFinally() throws Exception { + ControlFlowGraph cfg = checkCFGReduction(searchMethod(getResource("zip/data-java-eclipse-java-compiler-3.13.0.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinally")); + BasicBlock startBB = cfg.getStart(); + + assertNotNull(startBB); + + BasicBlock simpleBB = startBB.getNext(); + + assertEquals(simpleBB.getType(), TYPE_STATEMENTS); + + BasicBlock tryBB = simpleBB.getNext(); + + assertNotNull(tryBB); + assertEquals(tryBB.getType(), TYPE_TRY_ECLIPSE); + assertNotNull(tryBB.getExceptionHandlers()); + assertEquals(tryBB.getExceptionHandlers().size(), 1); + assertEquals(tryBB.getNext().getType(), TYPE_TRY_ECLIPSE); + assertEquals(tryBB.getNext().getNext().getType(), TYPE_STATEMENTS); + assertEquals(tryBB.getNext().getNext().getNext().getType(), TYPE_RETURN); + + ExceptionHandler eh0 = tryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_STATEMENTS); + + BasicBlock subTryBB = tryBB.getSub1(); + + assertEquals(subTryBB.getType(), TYPE_TRY_ECLIPSE); + assertNotNull(subTryBB.getExceptionHandlers()); + assertEquals(subTryBB.getExceptionHandlers().size(), 1); + assertEquals(subTryBB.getNext().getType(), TYPE_STATEMENTS); + assertEquals(subTryBB.getNext().getNext().getType(), TYPE_END); + + eh0 = subTryBB.getExceptionHandlers().get(0); + + assertNull(eh0.getInternalThrowableName()); + assertEquals(eh0.getBasicBlock().getType(), TYPE_THROW); + } + + @Test + public void testJdk118MethodTryTryFinallyFinallyTryFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.1.8.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinally")); + } + + @Test + public void testJdk131MethodTryTryFinallyFinallyTryFinally() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.3.1.zip"), "org/jd/core/test/TryCatchFinally", "methodTryTryFinallyFinallyTryFinally")); + } + + + protected ControlFlowGraph checkCFGReduction(Method method) throws Exception { + ControlFlowGraph cfg = ControlFlowGraphMaker.make(method); + + assertNotNull(cfg); + + BasicBlock root = cfg.getStart(); + + assertNotNull(root); + + String plantuml = ControlFlowGraphPlantUMLWriter.write(cfg); + System.out.println("Step 0: " + ControlFlowGraphPlantUMLWriter.writePlantUMLUrl(plantuml)); + + ControlFlowGraphGotoReducer.reduce(cfg); + + plantuml = ControlFlowGraphPlantUMLWriter.write(cfg); + System.out.println("Step 1: " + ControlFlowGraphPlantUMLWriter.writePlantUMLUrl(plantuml)); + + // --- Test natural loops --- // + BitSet[] dominators = ControlFlowGraphLoopReducer.buildDominatorIndexes(cfg); + List naturalLoops = ControlFlowGraphLoopReducer.identifyNaturalLoops(cfg, dominators); + + for (Loop loop : naturalLoops) { + System.out.println(loop); + } + + ControlFlowGraphLoopReducer.reduce(cfg); + plantuml = ControlFlowGraphPlantUMLWriter.write(cfg); + System.out.println("Step 2: " + ControlFlowGraphPlantUMLWriter.writePlantUMLUrl(plantuml)); + + BitSet visited = new BitSet(); + BitSet jsrTargets = new BitSet(); + + for (int i=0, count=3; i<5; i++, count++) { + boolean reduced = ControlFlowGraphReducer.reduce(visited, cfg.getStart(), jsrTargets); + + System.out.println("# of visited blocks: " + visited.cardinality()); + visited.clear(); + plantuml = ControlFlowGraphPlantUMLWriter.write(cfg); + System.out.println("Step " + count + ": " + ControlFlowGraphPlantUMLWriter.writePlantUMLUrl(plantuml)); + + if (reduced) { + break; + } + } + + checkFinalCFG(cfg); + + return cfg; + } + + protected static void checkFinalCFG(ControlFlowGraph cfg) { + List list = cfg.getBasicBlocks(); + + for (int i=0, len=list.size(); i reduction failed", basicBlock.getType() != TYPE_TRY_DECLARATION); + assertTrue("#" + basicBlock.getIndex() + " is a SWITCH_DECLARATION -> reduction failed", basicBlock.getType() != TYPE_SWITCH_DECLARATION); + assertTrue("#" + basicBlock.getIndex() + " is a CONDITIONAL -> reduction failed", basicBlock.getType() != TYPE_CONDITIONAL_BRANCH); + assertTrue("#" + basicBlock.getIndex() + " is a GOTO -> reduction failed", basicBlock.getType() != TYPE_GOTO); + + if (!basicBlock.matchType(GROUP_CONDITION)) { + for (BasicBlock predecessor : basicBlock.getPredecessors()) { + assertTrue("#" + predecessor.getIndex() + " is a predecessor of #" + basicBlock.getIndex() + " but #" + predecessor.getIndex() + " does not refer it", predecessor.contains(basicBlock)); + } + } + + if (basicBlock.matchType(TYPE_IF|TYPE_IF_ELSE)) { + assertTrue("#" + basicBlock.getIndex() + " is a IF or a IF_ELSE with a 'then' branch jumping to itself", basicBlock.getSub1() != basicBlock); + } + + if (basicBlock.getType() == TYPE_IF_ELSE) { + assertTrue("#" + basicBlock.getIndex() + " is a IF_ELSE with a 'else' branch jumping to itself", basicBlock.getSub2() != basicBlock); + } + + if (basicBlock.matchType(TYPE_TRY|TYPE_TRY_JSR)) { + boolean containsFinally = false; + HashSet exceptionNames = new HashSet<>(); + int maxOffset = 0; + + for (ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { + String name = exceptionHandler.getInternalThrowableName(); + int offset = exceptionHandler.getBasicBlock().getFromOffset(); + + if (name == null) { + assertFalse("#" + basicBlock.getIndex() + " contains multiple finally handlers", containsFinally); + containsFinally = true; + } else { + assertFalse("#" + basicBlock.getIndex() + " contains multiple handlers for " + name, exceptionNames.contains(name)); + exceptionNames.add(name); + } + + assertTrue("#" + basicBlock.getIndex() + " have an invalid exception handler", !exceptionHandler.getBasicBlock().matchType(GROUP_CONDITION)); + + if (maxOffset < offset) { + maxOffset = offset; + } + } + + for (ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { + BasicBlock bb = exceptionHandler.getBasicBlock(); + int offset = bb.getFromOffset(); + + if (maxOffset != offset) { + // Search last offset + BasicBlock next = bb.getNext(); + + while ((bb != next) && next.matchType(GROUP_SINGLE_SUCCESSOR|TYPE_RETURN|TYPE_RETURN_VALUE|TYPE_THROW) && (next.getPredecessors().size() == 1)) { + bb = next; + next = next.getNext(); + offset = bb.getFromOffset(); + } + + assertTrue("#" + basicBlock.getIndex() + " is a TRY or TRY_WITH_JST -> #" + exceptionHandler.getBasicBlock().getIndex() + " handler reduction failed", offset < maxOffset); + } + } + } + + if (basicBlock.getType() == TYPE_SWITCH) { + for (SwitchCase switchCase : basicBlock.getSwitchCases()) { + assertTrue("#" + basicBlock.getIndex() + " have an invalid switch case", !switchCase.getBasicBlock().matchType(GROUP_CONDITION)); + } + } + + if (!basicBlock.matchType(GROUP_CONDITION)) { + assertTrue("#" + basicBlock.getIndex() + " have an invalid next basic block", (basicBlock.getNext() == null) || !basicBlock.getNext().matchType(GROUP_CONDITION)); + assertTrue("#" + basicBlock.getIndex() + " have an invalid branch basic block", (basicBlock.getBranch() == null) || !basicBlock.getBranch().matchType(GROUP_CONDITION)); + assertTrue("#" + basicBlock.getIndex() + " have an invalid sub1 basic block", (basicBlock.getSub1() == null) || !basicBlock.getSub1().matchType(GROUP_CONDITION)); + assertTrue("#" + basicBlock.getIndex() + " have an invalid sub2 basic block", (basicBlock.getSub2() == null) || !basicBlock.getSub2().matchType(GROUP_CONDITION)); + } + } + + BitSet visited = new BitSet(list.size()); + SilentWatchDog watchdog = new SilentWatchDog(); + BasicBlock result = checkBasicBlock(visited, cfg.getStart(), watchdog); + + assertFalse("DELETED basic block detected -> reduction failed", (result != null) && (result.getType() == TYPE_DELETED)); + assertFalse("Cycle detected -> reduction failed", (result != null) && (result.getType() != TYPE_DELETED)); + } + + protected static BasicBlock checkBasicBlock(BitSet visited, BasicBlock basicBlock, SilentWatchDog watchdog) { + if ((basicBlock == null) || basicBlock.matchType(TYPE_END|TYPE_SWITCH_BREAK|TYPE_LOOP_START|TYPE_LOOP_CONTINUE|TYPE_LOOP_END|TYPE_RETURN)) { + return null; + } else { + BasicBlock result; + + visited.set(basicBlock.getIndex()); + + switch (basicBlock.getType()) { + case TYPE_DELETED: + return basicBlock; + case TYPE_SWITCH_DECLARATION: + case TYPE_SWITCH: + for (SwitchCase switchCase : basicBlock.getSwitchCases()) { + result = checkBasicBlock(visited, basicBlock, switchCase.getBasicBlock(), watchdog); + if (result != null) + return result; + } + return null; + case TYPE_TRY: + case TYPE_TRY_JSR: + result = checkBasicBlock(visited, basicBlock, basicBlock.getSub1(), watchdog); + if (result != null) + return result; + case TYPE_TRY_DECLARATION: + for (ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { + result = checkBasicBlock(visited, basicBlock, exceptionHandler.getBasicBlock(), watchdog); + if (result != null) + return result; + } + return checkBasicBlock(visited, basicBlock, basicBlock.getNext(), watchdog); + case TYPE_CONDITIONAL_BRANCH: + case TYPE_JSR: + result = checkBasicBlock(visited, basicBlock, basicBlock.getNext(), watchdog); + if (result != null) + return result; + return checkBasicBlock(visited, basicBlock, basicBlock.getBranch(), watchdog); + case TYPE_IF_ELSE: + case TYPE_TERNARY_OPERATOR: + result = checkBasicBlock(visited, basicBlock, basicBlock.getSub2(), watchdog); + if (result != null) + return result; + case TYPE_IF: + result = checkBasicBlock(visited, basicBlock, basicBlock.getCondition(), watchdog); + if (result != null) + return result; + case TYPE_LOOP: + result = checkBasicBlock(visited, basicBlock, basicBlock.getSub1(), watchdog); + if (result != null) + return result; + case TYPE_START: + case TYPE_STATEMENTS: + case TYPE_GOTO: + return checkBasicBlock(visited, basicBlock, basicBlock.getNext(), watchdog); + default: + return null; + } + } + } + + protected static BasicBlock checkBasicBlock(BitSet visited, BasicBlock parent, BasicBlock child, SilentWatchDog watchdog) { + if (!child.matchType(BasicBlock.GROUP_END) && !watchdog.silentCheck(parent, child)) { + return parent; + } + + return checkBasicBlock(visited, child, watchdog); + } + + protected static class SilentWatchDog extends WatchDog { + public boolean silentCheck(BasicBlock parent, BasicBlock child) { + if (!child.matchType(BasicBlock.GROUP_END)) { + Link link = new Link(parent, child); + + if (links.contains(link)) { + return false; + } + + links.add(link); + } + + return true; + } + } + + protected InputStream getResource(String zipName) { + return this.getClass().getResourceAsStream("/" + zipName); + } + + protected InputStream loadFile(String zipName) throws IOException { + return new FileInputStream(zipName); + } + + protected Method searchMethod(String internalTypeName, String methodName) throws Exception { + return searchMethod(loader, factory, parser, internalTypeName, methodName, null); + } + + protected Method searchMethod(InputStream is, String internalTypeName, String methodName) throws Exception { + return searchMethod(is, internalTypeName, methodName, null); + } + + protected Method searchMethod(InputStream is, String internalTypeName, String methodName, String methodDescriptor) throws Exception { + if (is == null) { + return null; + } else { + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker factory = new ObjectTypeMaker(loader); + SignatureParser parser = new SignatureParser(factory); + return searchMethod(loader, factory, parser, internalTypeName, methodName, methodDescriptor); + } + } + + protected Method searchMethod(Loader loader, ObjectTypeMaker factory, SignatureParser parser, String internalTypeName, String methodName, String methodDescriptor) throws Exception { + Message message = new Message(); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("loader", loader); + message.setHeader("objectTypeMaker", factory); + message.setHeader("signatureParser", parser); + + deserializer.process(message); + converter.process(message); + + CompilationUnit compilationUnit = message.getBody(); + + assertNotNull(compilationUnit); + + BaseTypeDeclaration typeDeclarations = compilationUnit.getTypeDeclarations(); + ClassFileBodyDeclaration bodyDeclaration = invokeGetter(typeDeclarations, "getBodyDeclaration"); + + for (ClassFileMemberDeclaration md : bodyDeclaration.getMethodDeclarations()) { + if (md instanceof ClassFileMethodDeclaration) { + ClassFileMethodDeclaration cfmd = (ClassFileMethodDeclaration) md; + if (cfmd.getName().equals(methodName)) { + if ((methodDescriptor == null) || cfmd.getDescriptor().equals(methodDescriptor)) { + return cfmd.getMethod(); + } + } + } else if (md instanceof ClassFileConstructorDeclaration) { + ClassFileConstructorDeclaration cfcd = (ClassFileConstructorDeclaration)md; + if (cfcd.getMethod().getName().equals(methodName)) { + if ((methodDescriptor == null) || cfcd.getDescriptor().equals(methodDescriptor)) { + return cfcd.getMethod(); + } + } + } else if (md instanceof ClassFileStaticInitializerDeclaration) { + ClassFileStaticInitializerDeclaration cfsid = (ClassFileStaticInitializerDeclaration)md; + if (cfsid.getMethod().getName().equals(methodName)) { + return cfsid.getMethod(); + } + } + } + + return null; + } +} diff --git a/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java b/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java new file mode 100644 index 00000000..78a85cd2 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java @@ -0,0 +1,1826 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.model.fragment.Fragment; +import org.jd.core.v1.model.javafragment.*; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.model.token.*; +import org.jd.core.v1.printer.PlainTextMetaPrinter; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util.JavaFragmentFactory; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.jd.core.v1.services.tokenizer.javafragmenttotoken.TestTokenizeJavaFragmentProcessor; +import org.jd.core.v1.util.DefaultList; +import org.jd.core.v1.util.PatternMaker; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class JavaFragmentToTokenTest extends TestCase { + public static final KeywordToken BOOLEAN = new KeywordToken("boolean"); + public static final KeywordToken CLASS = new KeywordToken("class"); + public static final KeywordToken CATCH = new KeywordToken("catch"); + public static final KeywordToken EXTENDS = new KeywordToken("extends"); + public static final KeywordToken FALSE = new KeywordToken("false"); + public static final KeywordToken FINALLY = new KeywordToken("finally"); + public static final KeywordToken IF = new KeywordToken("if"); + public static final KeywordToken IMPLEMENTS = new KeywordToken("implements"); + public static final KeywordToken INT = new KeywordToken("int"); + public static final KeywordToken NEW = new KeywordToken("new"); + public static final KeywordToken NULL = new KeywordToken("null"); + public static final KeywordToken PACKAGE = new KeywordToken("package"); + public static final KeywordToken PROTECTED = new KeywordToken("protected"); + public static final KeywordToken PUBLIC = new KeywordToken("public"); + public static final KeywordToken RETURN = new KeywordToken("return"); + public static final KeywordToken STATIC = new KeywordToken("static"); + public static final KeywordToken SUPER = new KeywordToken("super"); + public static final KeywordToken VOID = new KeywordToken("void"); + + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testIfReturn_0() throws Exception { + Message message = createMessageToTestIfReturn(0, 0); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "i = 1;"))); + } + + @Test + public void testIfReturn_1_3() throws Exception { + Message message = createMessageToTestIfReturn(1, 3); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 3); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "return;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "int i = 1;"))); + } + + @Test + public void testIfReturn_1_4() throws Exception { + Message message = createMessageToTestIfReturn(1, 4); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 4); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "return;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 4]", "int i = 1;"))); + } + + @Test + public void testIfAssignation_0() throws Exception { + Message message = createMessageToTestIfAssignation(0, 0, 0); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "i = 1;"))); + } + + @Test + public void testIfAssignation_1_2_3() throws Exception { + Message message = createMessageToTestIfAssignation(1, 2, 3); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 3); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 2]", "i = 0;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "i = 1;"))); + Assert.assertTrue(source.indexOf('{') == -1); + } + + @Test + public void testIfAssignation_1_3_5() throws Exception { + Message message = createMessageToTestIfAssignation(1, 3, 5); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 5); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "{"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "i = 0;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 5: 5]", "i = 1;"))); + } + + @Test + public void testClassAndFieldDeclarationWithoutImports_0() throws Exception { + Message message = createMessageToTestClassDeclarationWithoutImports(0); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_0() throws Exception { + Message message = createMessageToTestClassDeclaration(0); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_1() throws Exception { + Message message = createMessageToTestClassDeclaration(1); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 1); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 1] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.indexOf("[ 2: 0] -->") != -1); + } + + @Test + public void testClassAndFieldDeclaration_2() throws Exception { + Message message = createMessageToTestClassDeclaration(2); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 2); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 2]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_3() throws Exception { + Message message = createMessageToTestClassDeclaration(3); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 3); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "protected int a"))); + Assert.assertTrue(source.indexOf("[ 4: 0] } -->") != -1); + } + + @Test + public void testClassAndFieldDeclaration_4() throws Exception { + Message message = createMessageToTestClassDeclaration(4); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 4); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 4]", "protected int a"))); + Assert.assertTrue(source.indexOf("[ 5: 0] } -->") != -1); + } + + @Test + public void testClassAndFieldDeclaration_5() throws Exception { + Message message = createMessageToTestClassDeclaration(5); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 5); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 5: 5]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_6() throws Exception { + Message message = createMessageToTestClassDeclaration(6); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 6); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 5: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 6]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_7() throws Exception { + Message message = createMessageToTestClassDeclaration(7); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 7); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 7]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_8() throws Exception { + Message message = createMessageToTestClassDeclaration(8); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 8); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 8]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_9() throws Exception { + Message message = createMessageToTestClassDeclaration(9); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 9); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 9]", "protected int a"))); + } + + @Test + public void testClassAndFieldDeclaration_10() throws Exception { + Message message = createMessageToTestClassDeclaration(10); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 10); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 10]", "protected int a"))); + } + + @Test + public void testClassAndMethodDeclaration_3() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(3); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 3); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "super(i);"))); + } + + @Test + public void testClassAndMethodDeclaration_4() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(4); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 4); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "public TokenWriterTest", "(int i)"))); + } + + @Test + public void testClassAndMethodDeclaration_8() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(8); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 8); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "public TokenWriterTest", "(int i)"))); + } + + @Test + public void testClassAndMethodDeclaration_9() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(9); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 9); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "public TokenWriterTest", "(int i)"))); + } + + @Test + public void testClassAndMethodDeclaration_10() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(10); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 10); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 10]", "super"))); + } + + @Test + public void testClassAndMethodDeclaration_11() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(11); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 11); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 0]", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 11: 11]", "super"))); + } + + @Test + public void testClassAndMethodDeclaration_12() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(12); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 12); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 11: 0]", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 12: 12]", "super"))); + } + + @Test + public void testClassAndMethodDeclaration_14() throws Exception { + Message message = createMessageToTestClassAndMethodDeclaration(14); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 14); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 0]", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 11: 0]", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 13: 0]", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("[ 14: 14]", "super"))); + } + + @Test + public void testLayout() throws Exception { + Message message = createSimpleMessage(1); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 22); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 22: 22]", "System", "println", "(i);"))); + } + + @Test + public void testLayoutWithoutLineNumber() throws Exception { + Message message = createSimpleMessage(0); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 15: 0]", "public Object", "nextElement"))); + } + + @Test + public void testLayoutWithStretchedfFragments_2() throws Exception { + Message message = createSimpleMessage(2); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 44); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 44: 44]") != -1); + } + + @Test + public void testLayoutWithStretchedfFragments_3() throws Exception { + Message message = createSimpleMessage(3); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 66); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.indexOf("[ 66: 66]") != -1); + } + + @Test + public void testMoveDown() throws Exception { + Message message = createMessageToTestMoveDown(); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 8); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "public static void main"))); + } + + @Test + public void testLinkedBlocks_16() throws Exception { + Message message = createMessageToTestLinkedBlocks(6, 9, 11, 13, 16); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 16); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 16: 16]", "i = 4;"))); + } + + @Test + public void testLinkedBlocks_22() throws Exception { + Message message = createMessageToTestLinkedBlocks(7, 11, 15, 19, 22); + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 22); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 22: 22]", "i = 4;"))); + } + + /** + * Generate : + * [ 1: 0 ] <-- 0,1,2147483647:4 + * [ 2: lineNumber1] -->if (args == null)<-- 0,1,2:5 + * [ 3: 0 ] -->return;<-- 0,0,2:5 --><-- 0,1,2147483647:4 + * [ 4: lineNumber2] -->int i = 1;<-- 0,1,2147483647:4 + * [ 5: 0 ] --> + * + * @param lineNumber1 + * @param lineNumber2 + * @return A message + * @throws Exception + */ + public Message createMessageToTestIfReturn(int lineNumber1, int lineNumber2) throws Exception { + DefaultList fragments = new DefaultList<>(); + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + List tokens = Arrays.asList( + IF, + TextToken.SPACE, + TextToken.LEFTROUNDBRACKET, + new LineNumberToken(lineNumber1), + new TextToken("args == "), + NULL, + TextToken.RIGHTROUNDBRACKET + ); + + if (lineNumber1 == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + StartSingleStatementBlockFragment start = JavaFragmentFactory.addStartSingleStatementBlock(fragments); + // return;\n + fragments.add(new TokensFragment( + RETURN, + TextToken.SEMICOLON + )); + // End of if (args == null) + JavaFragmentFactory.addEndSingleStatementBlock(fragments, start); + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + tokens = Arrays.asList( + INT, + new LineNumberToken(lineNumber2), + new TextToken(" i = 1;") + ); + + if (lineNumber2 == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + Message message = new Message(fragments); + message.setHeader("maxLineNumber", Integer.valueOf(lineNumber2)); + + return message; + } + + /** + * Generate : + * [ 1: 0 ] <-- 0,1,2147483647:4 + * [ 2: lineNumber1] -->if (args == null)<-- 0,1,2:5 + * [ 3: lineNumber2] -->i = 0;<-- 0,0,2:5 --><-- 0,1,2147483647:4 + * [ 4: lineNumber3] -->i = 1;<-- 0,1,2147483647:4 + * [ 5: 0 ] --> + * + * @param lineNumber1 + * @param lineNumber2 + * @param lineNumber3 + * @return A message + * @throws Exception + */ + public Message createMessageToTestIfAssignation(int lineNumber1, int lineNumber2, int lineNumber3) throws Exception { + DefaultList fragments = new DefaultList<>(); + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + List tokens = Arrays.asList( + IF, + TextToken.SPACE, + TextToken.LEFTROUNDBRACKET, + new LineNumberToken(lineNumber1), + new TextToken("args == "), + NULL, + TextToken.RIGHTROUNDBRACKET + ); + + if (lineNumber1 == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + StartSingleStatementBlockFragment start = JavaFragmentFactory.addStartSingleStatementBlock(fragments); + // i = 0;\n + tokens = Arrays.asList( + new LineNumberToken(lineNumber2), + new TextToken("i = 0;") + ); + + if (lineNumber2 == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + // End of if (args == null) + JavaFragmentFactory.addEndSingleStatementBlock(fragments, start); + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + tokens = Arrays.asList( + new LineNumberToken(lineNumber3), + new TextToken("i = 1;") + ); + + if (lineNumber3 == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + Message message = new Message(fragments); + message.setHeader("maxLineNumber", Integer.valueOf(lineNumber3)); + + return message; + } + + public Message createMessageToTestClassDeclaration(int lineNumber) throws Exception { + DefaultList fragments = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + fragments.add(new TokensFragment( + PACKAGE, + new TextToken(" org.jd.core.v1.service.writer;") + )); + + JavaFragmentFactory.addSpacerAfterPackage(fragments); + + // import java.util.ArrayList;\n + // import static org.junit.Assert.*;\n\n + ImportsFragment imports = JavaFragmentFactory.newImportsFragment(); + imports.addImport("java/util/ArrayList", "java.util.ArrayList"); + imports.addImport("org/junit/Assert/*", "org.junit.Assert.*"); + imports.initLineCounts(); + fragments.add(imports); + + JavaFragmentFactory.addSpacerAfterImports(fragments); + JavaFragmentFactory.addSpacerBeforeMainDeclaration(fragments); + + // public class TokenWriterTest extends Test implements Serializable, Comparable, Cloneable {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + CLASS, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null), + StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK + )); + + JavaFragmentFactory.addSpacerBeforeExtends(fragments); + + fragments.add(new TokensFragment( + EXTENDS, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/jd/core/v1/service/test/Test", "Test", null, null) + )); + + JavaFragmentFactory.addSpacerBeforeImplements(fragments); + + fragments.add(new TokensFragment( + IMPLEMENTS, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/io/Serializable", "Serializable", null, null), + TextToken.COMMA_SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Comparable", "Comparable", null, null), + TextToken.LEFTANGLEBRACKET, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/jd/core/v1/service/test/Test", "Test", null, null), + TextToken.RIGHTANGLEBRACKET, + TextToken.COMMA_SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Cloneable", "Cloneable", null, null), + EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK + )); + + StartBodyFragment classStart = JavaFragmentFactory.addStartTypeBody(fragments); + + // protected int a = 0; + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); + + List tokens = Arrays.asList( + PROTECTED, + TextToken.SPACE, + INT, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.FIELD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "a", "I"), + new TextToken(" = "), + new LineNumberToken(lineNumber), + new NumericConstantToken("0"), + TextToken.SEMICOLON + ); + + if (lineNumber == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + JavaFragmentFactory.addEndTypeBody(fragments, classStart); + + Message message = new Message(fragments); + message.setHeader("maxLineNumber", Integer.valueOf(lineNumber)); + + return message; + } + + public Message createMessageToTestClassDeclarationWithoutImports(int lineNumber) throws Exception { + DefaultList fragments = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + fragments.add(new TokensFragment( + PACKAGE, + new TextToken(" org.jd.core.v1.service.writer;") + )); + + JavaFragmentFactory.addSpacerAfterPackage(fragments); + + // public class TokenWriterTest extends Test implements Serializable, Comparable, Cloneable {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + CLASS, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null), + StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK + )); + + JavaFragmentFactory.addSpacerBeforeExtends(fragments); + + fragments.add(new TokensFragment( + EXTENDS, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/jd/core/v1/service/test/Test", "Test", null, null) + )); + + JavaFragmentFactory.addSpacerBeforeImplements(fragments); + + fragments.add(new TokensFragment( + IMPLEMENTS, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/io/Serializable", "Serializable", null, null), + TextToken.COMMA_SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Comparable", "Comparable", null, null), + TextToken.LEFTANGLEBRACKET, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/jd/core/v1/service/test/Test", "Test", null, null), + TextToken.RIGHTANGLEBRACKET, + TextToken.COMMA_SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Cloneable", "Cloneable", null, null), + EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK + )); + + StartBodyFragment classStart = JavaFragmentFactory.addStartTypeBody(fragments); + + // protected int a = 0; + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); + + List tokens = Arrays.asList( + PROTECTED, + TextToken.SPACE, + INT, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.FIELD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "a", "I"), + new TextToken(" = "), + new LineNumberToken(lineNumber), + new NumericConstantToken("0"), + TextToken.SEMICOLON + ); + + if (lineNumber == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + JavaFragmentFactory.addEndTypeBody(fragments, classStart); + + Message message = new Message(fragments); + message.setHeader("maxLineNumber", Integer.valueOf(lineNumber)); + + return message; + } + + /* + * package org.jd.core.v1.service.writer;<-- 0,2,1 + * + * --><-- 0,M,0 import java.util.ArrayList; + * import org.junit.Assert.*; + * --><-- 0,1,1 + * --><-- 0,++,5 -->public class TokenWriterTest <-- 0,1,4 -->extends Test <-- 0,1,3 -->implements Serializable, Comparable, Cloneable <-- { 0,2,2 + * --> public TokenWriterTest(int i) {<-- { 0,2,5 + * --> super(i); + * } + * } + */ + public Message createMessageToTestClassAndMethodDeclaration(int lineNumber) throws Exception { + DefaultList fragments = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + fragments.add(new TokensFragment( + PACKAGE, + new TextToken(" org.jd.core.v1.service.writer;") + )); + + JavaFragmentFactory.addSpacerAfterPackage(fragments); + + // import java.util.ArrayList;\n + // import static org.junit.Assert.*;\n\n + ImportsFragment imports = JavaFragmentFactory.newImportsFragment(); + imports.addImport("java/util/ArrayList", "java.util.ArrayList"); + imports.addImport("org/junit/Assert/*", "org.junit.Assert.*"); + imports.initLineCounts(); + fragments.add(imports); + + JavaFragmentFactory.addSpacerAfterImports(fragments); + JavaFragmentFactory.addSpacerBeforeMainDeclaration(fragments); + + // public class TokenWriterTest extends Test implements Serializable, Comparable, Cloneable {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + CLASS, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null), + StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK + )); + + JavaFragmentFactory.addSpacerBeforeExtends(fragments); + + fragments.add(new TokensFragment( + EXTENDS, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/jd/core/v1/service/test/Test", "Test", null, null) + )); + + JavaFragmentFactory.addSpacerBeforeImplements(fragments); + + fragments.add(new TokensFragment( + IMPLEMENTS, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/io/Serializable", "Serializable", null, null), + TextToken.COMMA_SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Comparable", "Comparable", null, null), + TextToken.LEFTANGLEBRACKET, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/jd/core/v1/service/test/Test", "Test", null, null), + TextToken.RIGHTANGLEBRACKET, + TextToken.COMMA_SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Cloneable", "Cloneable", null, null), + EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK + )); + + StartBodyFragment startMainClass = JavaFragmentFactory.addStartTypeBody(fragments); + + // public TokenWriterTest(int i) { + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.CONSTRUCTOR_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", "(I)V"), + TextToken.LEFTROUNDBRACKET, + INT, + TextToken.SPACE, + new TextToken("i"), + TextToken.RIGHTROUNDBRACKET + )); + + StartBodyFragment startConstructor = JavaFragmentFactory.addStartMethodBody(fragments); + + fragments.add(new LineNumberTokensFragment( + new LineNumberToken(lineNumber), + SUPER, + TextToken.LEFTROUNDBRACKET, + new TextToken("i"), + TextToken.RIGHTROUNDBRACKET, + TextToken.SEMICOLON + )); + + JavaFragmentFactory.addEndMethodBody(fragments, startConstructor); + JavaFragmentFactory.addEndTypeBody(fragments, startMainClass); + + Message message = new Message(fragments); + message.setHeader("maxLineNumber", Integer.valueOf(lineNumber)); + + return message; + } + + /* + * package org.jd.core.v1.service.writer;<-- 0,2,1 + * + * --><-- 0,M,0 import java.util.ArrayList; + * import org.junit.Assert.*; + * --><-- 0,1,1 + * --><-- 0,++,5 -->public class TokenWriterTest<-- { 0,2,2 + * --> public static void main(String[] args) {<-- { 0,2,5 + * --> if (args == null);<-- { 0,2,8 + * --><-- 0,++,9 --> return;<-- 0,++,8 --><-- + * } 0,2,8 --><-- 0,++,8 + * --> int i = call(\n + * "aaaa",\n + * b,\n + * new Enumeration()<-- { 0,2,2 + * --> public boolean hasMoreElements()<-- { 0,2,5 + * --> return false; <-- + * } 0,2,7 --><-- 0,1,4 + * --><-- 0,++,7 + * --> public Object nextElement()<-- { 0,2,5 + * --> return null; <-- + * } 0,2,7 --><-- + * } 0,2,2 -->,<-- 0,++,8 + * --> c);<-- 0,++,8 + * --> System.out.println(i);<-- + * } 0,2,7 --><-- + * } 0,2,2 --> + */ + public Message createSimpleMessage(int factor) { + DefaultList fragments = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + fragments.add(new TokensFragment( + PACKAGE, + new TextToken(" org.jd.core.v1.service.writer;") + )); + + JavaFragmentFactory.addSpacerAfterPackage(fragments); + + // import java.util.ArrayList;\n + // import static org.junit.Assert.*;\n\n + ImportsFragment imports = JavaFragmentFactory.newImportsFragment(); + imports.addImport("java/util/ArrayList", "java.util.ArrayList"); + imports.addImport("org/junit/Assert/*", "org.junit.Assert.*"); + imports.initLineCounts(); + fragments.add(imports); + + JavaFragmentFactory.addSpacerAfterImports(fragments); + JavaFragmentFactory.addSpacerBeforeMainDeclaration(fragments); + + // public class TokenWriterTest {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + CLASS, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null) + )); + + StartBodyFragment startMainClass = JavaFragmentFactory.addStartTypeBody(fragments); + + // public static void main(String[] args) {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + STATIC, + TextToken.SPACE, + VOID, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), + TextToken.LEFTROUNDBRACKET, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), + new TextToken("[] args)") + )); + + StartBodyFragment startMainMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); + + // if (args == null)\n + List tokens = Arrays.asList( + IF, + TextToken.SPACE, + TextToken.LEFTROUNDBRACKET, + new LineNumberToken(8 * factor), + new TextToken("args == "), + NULL, + TextToken.RIGHTROUNDBRACKET + ); + + if (factor == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + StartSingleStatementBlockFragment startIfBlock = JavaFragmentFactory.addStartSingleStatementBlock(fragments); + + // return;\n + fragments.add(new TokensFragment( + RETURN, + TextToken.SEMICOLON + )); + + // End of if (args == null) + JavaFragmentFactory.addEndSingleStatementBlock(fragments, startIfBlock); + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + // int i = call(\n + // "aaaa",\n + // b,\n + // new Enumeration() {\n + tokens = Arrays.asList( + INT, + new LineNumberToken(10 * factor), + new TextToken(" i = "), + new ReferenceToken(ReferenceToken.METHOD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "call", "(IILjava/util/Enumeration;I)V", "org/jd/core/v1/service/test/TokenWriterTest"), + StartBlockToken.START_PARAMETERS_BLOCK, + new LineNumberToken(11 * factor), + new StringConstantToken("aaaa", "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.COMMA, + TextToken.SPACE, + new LineNumberToken(12 * factor), + new TextToken("b,"), + TextToken.SPACE, + new LineNumberToken(13 * factor), + NEW, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/util/Enumeration", "java.util.Enumeration", null, "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.LEFTRIGHTROUNDBRACKETS + ); + + if (factor == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + StartBodyFragment startEnumerationClass = JavaFragmentFactory.addStartTypeBody(fragments); + + // public boolean hasMoreElements() {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + BOOLEAN, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest$1", "hasMoreElements", "()Z"), + TextToken.LEFTRIGHTROUNDBRACKETS + )); + + StartBodyFragment startHasMoreElementsMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); + + // return false;\n + tokens = Arrays.asList( + RETURN, + TextToken.SPACE, + new LineNumberToken(15 * factor), + FALSE, + TextToken.SEMICOLON + ); + + if (factor == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + // }\n // End of public boolean hasMoreElements() + JavaFragmentFactory.addEndMethodBody(fragments, startHasMoreElementsMethodBody); + + JavaFragmentFactory.addSpacerBetweenMembers(fragments); + + // public Object nextElement() {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Object", "Object", null, "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.SPACE, + new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest$1", "nextElement", "()Ljava/lang/Object;"), + TextToken.LEFTRIGHTROUNDBRACKETS + )); + + StartBodyFragment startNextElementMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); + + // return null;\n + tokens = Arrays.asList( + RETURN, + TextToken.SPACE, + new LineNumberToken(18 * factor), + NULL, + TextToken.SEMICOLON + ); + + if (factor == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + // } // End of public Object nextElement() + JavaFragmentFactory.addEndMethodBody(fragments, startNextElementMethodBody); + + // \n}, // End of new Enumeration() + JavaFragmentFactory.addEndSubTypeBodyInParameter(fragments, startEnumerationClass); + + // c); // End of call(... + // System.out.println(i); + tokens = Arrays.asList( + new LineNumberToken(21 * factor), + new TextToken("c"), + EndBlockToken.END_PARAMETERS_BLOCK, + TextToken.SEMICOLON, + NewLineToken.NEWLINE_1, + new LineNumberToken(22 * factor), + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/System", "System", null, "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.DOT, + new ReferenceToken(ReferenceToken.FIELD_FLAG, "java/lang/System", "out", "java/io/PrintStream", "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.DOT, + new ReferenceToken(ReferenceToken.METHOD_FLAG, "java/io/PrintStream", "println", "(I)V", "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.LEFTROUNDBRACKET, + new TextToken("i"), + TextToken.RIGHTROUNDBRACKET, + TextToken.SEMICOLON + ); + + if (factor == 0) { + fragments.add(new TokensFragment(tokens)); + } else { + fragments.add(new LineNumberTokensFragment(tokens)); + } + + // \n} // End of public static void main(String[] args) + JavaFragmentFactory.addEndMethodBody(fragments, startMainMethodBody); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + // } // End of public class TokenWriterTest + JavaFragmentFactory.addEndTypeBody(fragments, startMainClass); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + Message message = new Message(fragments); + if (factor != 0) + message.setHeader("maxLineNumber", Integer.valueOf(22 * factor)); + + return message; + } + + public Message createMessageToTestMoveDown() { + DefaultList fragments = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + fragments.add(new TokensFragment( + PACKAGE, + new TextToken(" org.jd.core.v1.service.writer;") + )); + + JavaFragmentFactory.addSpacerAfterImports(fragments); + JavaFragmentFactory.addSpacerBeforeMainDeclaration(fragments); + + // public class TokenWriterTest {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + CLASS, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null) + )); + + StartBodyFragment startMainClass = JavaFragmentFactory.addStartTypeBody(fragments); + + // public static int TIMESTAMP = System.currentTimeMillis(); + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); + fragments.add(new LineNumberTokensFragment( + PUBLIC, + TextToken.SPACE, + STATIC, + TextToken.SPACE, + INT, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.FIELD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TIMESTAMP", "I"), + new TextToken(" = "), + new LineNumberToken(4), + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/System", "System", null, "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.DOT, + new ReferenceToken(ReferenceToken.METHOD_FLAG, "java/lang/System", "currentTimeMillis", "()J", "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.LEFTRIGHTROUNDBRACKETS, + TextToken.SEMICOLON + )); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + JavaFragmentFactory.addSpacerBetweenMembers(fragments); + + // protected int a; + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); + fragments.add(new TokensFragment( + PROTECTED, + TextToken.SPACE, + INT, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.FIELD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "a", "I"), + TextToken.SEMICOLON + )); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + JavaFragmentFactory.addSpacerBetweenMembers(fragments); + + // protected int b; + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); + fragments.add(new TokensFragment( + PROTECTED, + TextToken.SPACE, + INT, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.FIELD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "b", "I"), + TextToken.SEMICOLON + )); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + JavaFragmentFactory.addSpacerBetweenMembers(fragments); + + // protected int c; + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); + fragments.add(new TokensFragment( + PROTECTED, + TextToken.SPACE, + INT, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.FIELD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "c", "I"), + TextToken.SEMICOLON + )); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + JavaFragmentFactory.addSpacerBetweenMembers(fragments); + + // public static void main(String[] args) {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + STATIC, + TextToken.SPACE, + VOID, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), + TextToken.LEFTROUNDBRACKET, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), + new TextToken("[] args)") + )); + + StartBodyFragment startMainMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); + //StartBodyFragment startMainMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); + + // System.out.println(TIMESTAMP); + fragments.add(new LineNumberTokensFragment( + new LineNumberToken(8), + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/System", "System", null, "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.DOT, + new ReferenceToken(ReferenceToken.FIELD_FLAG, "java/lang/System", "out", "java/io/PrintStream", "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.DOT, + new ReferenceToken(ReferenceToken.METHOD_FLAG, "java/io/PrintStream", "println", "(I)V", "org/jd/core/v1/service/test/TokenWriterTest"), + TextToken.LEFTROUNDBRACKET, + new TextToken("TIMESTAMP"), + TextToken.RIGHTROUNDBRACKET, + TextToken.SEMICOLON + )); + + // \n} + JavaFragmentFactory.addEndMethodBody(fragments, startMainMethodBody); + //JavaFragmentFactory.addEndMethodBody(fragments, startMainMethodBody); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + // } + JavaFragmentFactory.addEndTypeBody(fragments, startMainClass); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + Message message = new Message(fragments); + message.setHeader("maxLineNumber", Integer.valueOf(8)); + //message.setStart("containsByteCode", Boolean.TRUE); + + return message; + } + + /** + * Generate: + * [ 1: 0 ] package org.jd.core.v1.service.writer;<-- 0,2,2:9 + * [ 2: 0 ] + * [ 3: 0 ] -->public class TokenWriterTest<-- 0,1,2:2 + * [ 4: 0 ] { + * [ 5: 0 ] -->public static void main(String[] args)<-- 0,0,2:11 { + * [ 6: lineNumber1] -->int i = 0;<-- 0,1,2147483647:4 + * [ 7: 0 ] + * [ 8: 0 ] -->try<-- 0,1,2:5 { + * [ 9: lineNumber2] --><-- 0,0,2147483647:19 -->i = 1;<-- 0,0,2147483647:18 --><-- 0,1,2:5 + * [ 10: 0 ] } -->catch (RuntimeException e)<-- 0,1,2:5 { + * [ 11: lineNumber3] --><-- 0,0,2147483647:19 -->i = 2;<-- 0,0,2147483647:18 --><-- 0,1,2:5 + * [ 12: 0 ] } -->finally<-- 0,1,2:5 { + * [ 13: lineNumber4] --><-- 0,0,2147483647:19 -->i = 3;<-- 0,0,2147483647:18 --><-- 0,1,2:5 + * [ 14: 0 ] } --><-- 0,1,2147483647:4 + * [ 15: 0 ] + * [ 16: lineNumber5] -->i = 4;<-- 0,1,1:3 + * [ 17: 0 ] } --><-- 0,1,1:1 + * [ 18: 0 ] } --> + * + * @param lineNumber1 + * @param lineNumber2 + * @param lineNumber3 + * @param lineNumber4 + * @param lineNumber5 + * @return + */ + public Message createMessageToTestLinkedBlocks(int lineNumber1, int lineNumber2, int lineNumber3, int lineNumber4, int lineNumber5) { + DefaultList fragments = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + fragments.add(new TokensFragment( + PACKAGE, + new TextToken(" org.jd.core.v1.service.writer;") + )); + + JavaFragmentFactory.addSpacerAfterImports(fragments); + JavaFragmentFactory.addSpacerBeforeMainDeclaration(fragments); + + // public class TokenWriterTest {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + CLASS, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null) + )); + + StartBodyFragment startMainClass = JavaFragmentFactory.addStartTypeBody(fragments); + + // public static void main(String[] args) {\n + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); + fragments.add(new TokensFragment( + PUBLIC, + TextToken.SPACE, + STATIC, + TextToken.SPACE, + VOID, + TextToken.SPACE, + new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), + TextToken.LEFTROUNDBRACKET, + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), + new TextToken("[] args)") + )); + + StartBodyFragment startMainMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); + + // int i = 0; + fragments.add(new LineNumberTokensFragment( + new LineNumberToken(lineNumber1), + INT, + new TextToken(" i = 0;") + )); + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + // try { + StartStatementsBlockFragment.Group group = JavaFragmentFactory.addStartStatementsTryBlock(fragments); + + // i = 1; + fragments.add(new LineNumberTokensFragment( + new LineNumberToken(lineNumber2), + new TextToken("i = 1;") + )); + + JavaFragmentFactory.addEndStatementsBlock(fragments, group); + + // catch (RuntimeException e) + fragments.add(new TokensFragment( + CATCH, + new TextToken(" ("), + new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/RuntimeException", "RuntimeException", null, "org/jd/core/v1/service/test/TokenWriterTest"), + new TextToken(" e)") + )); + + JavaFragmentFactory.addStartStatementsBlock(fragments, group); + + // i = 2; + fragments.add(new LineNumberTokensFragment( + new LineNumberToken(lineNumber3), + new TextToken("i = 2;") + )); + + JavaFragmentFactory.addEndStatementsBlock(fragments, group); + + // finally + fragments.add(new TokensFragment( + FINALLY + )); + + JavaFragmentFactory.addStartStatementsBlock(fragments, group); + + // i = 3; + fragments.add(new LineNumberTokensFragment( + new LineNumberToken(lineNumber4), + new TextToken("i = 3;") + )); + + JavaFragmentFactory.addEndStatementsBlock(fragments, group); + + JavaFragmentFactory.addSpacerBetweenStatements(fragments); + + // i = 4; + fragments.add(new LineNumberTokensFragment( + new LineNumberToken(lineNumber5), + new TextToken("i = 4;") + )); + + // \n} + JavaFragmentFactory.addEndMethodBody(fragments, startMainMethodBody); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + // } + JavaFragmentFactory.addEndTypeBody(fragments, startMainClass); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + + Message message = new Message(fragments); + message.setHeader("maxLineNumber", Integer.valueOf(8)); + //message.setStart("containsByteCode", Boolean.TRUE); + + return message; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java new file mode 100644 index 00000000..24a78a42 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java @@ -0,0 +1,665 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.loader.NopLoader; +import org.jd.core.v1.model.javasyntax.CompilationUnit; +import org.jd.core.v1.model.javasyntax.declaration.*; +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.Types; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextMetaPrinter; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +@SuppressWarnings("unchecked") +public class JavaSyntaxToJavaSourceTest extends TestCase { + + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testClassDeclaration() throws Exception { + ObjectType stringArrayType = new ObjectType("java/lang/String", "java.lang.String", "String", 1); + ObjectType printStreamType = new ObjectType("java/io/PrintStream", "java.io.PrintStream", "PrintStream"); + + CompilationUnit compilationUnit = new CompilationUnit( + new ClassDeclaration( + ClassDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/TokenWriterTest", + "TokenWriterTest", + new BodyDeclaration( + "org/jd/core/v1/service/test/TokenWriterTest", + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, + "main", + PrimitiveType.TYPE_VOID, + new FormalParameter(ObjectType.TYPE_STRING.createType(1), "args"), + "([Ljava/lang/String;)V", + new Statements( + new IfStatement( + new BinaryOperatorExpression( + 8, + PrimitiveType.TYPE_BOOLEAN, + new LocalVariableReferenceExpression(8, stringArrayType, "args"), + "==", + new NullExpression(8, stringArrayType), + 9 + ), + ReturnStatement.RETURN + ), + new LocalVariableDeclarationStatement( + PrimitiveType.TYPE_INT, + new LocalVariableDeclarator( + "i", + new ExpressionVariableInitializer( + new MethodInvocationExpression( + 10, + PrimitiveType.TYPE_INT, + new ThisExpression(10, new ObjectType("org/jd/core/v1/service/test/TokenWriterTest", "org.jd.core.v1.service.writer.TokenWriterTest", "TokenWriterTest")), + "org/jd/core/v1/service/test/TokenWriterTest", + "call", + "(Ljava/lang/String;ILjava/util/Enumeration;C)I", + new Expressions( + new StringConstantExpression(11, "aaaa"), + new LocalVariableReferenceExpression(12, PrimitiveType.TYPE_INT, "b"), + new NewExpression( + 13, + new ObjectType("java/util/Enumeration", "java.util.Enumeration", "Enumeration"), + new BodyDeclaration( + "java/util/Enumeration", + new MemberDeclarations( + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC, + "hasMoreElements", + PrimitiveType.TYPE_BOOLEAN, + "()Z", + new ReturnExpressionStatement(new BooleanExpression(15, false)) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC, + "nextElement", + ObjectType.TYPE_OBJECT, + "()Ljava/lang/Object;", + new ReturnExpressionStatement(new NullExpression(18, ObjectType.TYPE_OBJECT)) + ) + ) + ) + ), + new LocalVariableReferenceExpression(21, PrimitiveType.TYPE_CHAR, "c") + ) + ) + ) + ) + ), + new ExpressionStatement( + new MethodInvocationExpression( + 22, + PrimitiveType.TYPE_VOID, + new FieldReferenceExpression( + 22, + printStreamType, + new ObjectTypeReferenceExpression(22, new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "out", + "Ljava/io/PrintStream;" + ), + "java/io/PrintStream", + "println", + "(I)V", + new LocalVariableReferenceExpression(22, PrimitiveType.TYPE_INT, "i") + ) + ) + ) + ) + ) + ) + ); + + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + Message message = new Message(compilationUnit); + + message.setHeader("mainInternalTypeName", "org/jd/core/v1/service/test/TokenWriterTest"); + message.setHeader("loader", new NopLoader()); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + message.setHeader("maxLineNumber", 22); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + System.out.println("- - - - - - - - "); + System.out.print(source); + System.out.println("- - - - - - - - "); + + Assert.assertTrue(source.indexOf("[ 22: 22]") != -1); + Assert.assertTrue(source.indexOf("java.lang.System") == -1); + } + + @Test + public void testInterfaceDeclaration() throws Exception { + ObjectType cloneableType = new ObjectType("java/lang/Cloneable", "java.lang.Cloneable", "Cloneable"); + ObjectType stringType = new ObjectType("java/lang/String", "java.lang.String", "String"); + ObjectType listType = new ObjectType("java/util/List", "java.util.List", "List", stringType); + + CompilationUnit compilationUnit = new CompilationUnit( + new InterfaceDeclaration( + InterfaceDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/InterfaceTest", + "InterfaceTest", + new Types(listType, cloneableType) + ) + ); + + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Message message = new Message(compilationUnit); + + message.setHeader("mainInternalTypeName", "org/jd/core/v1/service/test/InterfaceTest"); + message.setHeader("loader", new NopLoader()); + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + System.out.println("- - - - - - - - "); + System.out.print(source); + System.out.println("- - - - - - - - "); + + Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.test;") != -1); + Assert.assertTrue(source.indexOf("interface InterfaceTest") != -1); + Assert.assertTrue(source.indexOf("extends List") != -1); + Assert.assertTrue(source.indexOf("MONDAY") != -1); + } + + @Test + public void testEnumPlanetDeclaration() throws Exception { + Type cloneableType = new ObjectType("java/lang/Cloneable", "java.lang.Cloneable", "Cloneable"); + Type stringType = ObjectType.TYPE_STRING; + Type arrayOfStringType = stringType.createType(1); + Type listType = new ObjectType("java/util/List", "java.util.List", "List", stringType); + Type printStreamType = new ObjectType("java/io/PrintStream", "java.io.PrintStream", "PrintStream"); + Type planetType = new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet"); + ThisExpression thisExpression = new ThisExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")); + + CompilationUnit compilationUnit = new CompilationUnit( + new EnumDeclaration( + EnumDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/Planet", + "Planet", + Arrays.asList( + new EnumDeclaration.Constant( + "MERCURY", + new Expressions( + new DoubleConstantExpression(3.303e+23), + new DoubleConstantExpression(2.4397e6) + ) + ), + new EnumDeclaration.Constant( + "VENUS", + new Expressions( + new DoubleConstantExpression(4.869e+24), + new DoubleConstantExpression(6.0518e6) + ) + ), + new EnumDeclaration.Constant( + "EARTH", + new Expressions( + new DoubleConstantExpression(5.976e+24), + new DoubleConstantExpression(6.37814e6) + ) + ) + ), + new BodyDeclaration( + "org/jd/core/v1/service/test/Planet", + new MemberDeclarations( + new FieldDeclaration(FieldDeclaration.FLAG_PRIVATE | FieldDeclaration.FLAG_FINAL, PrimitiveType.TYPE_DOUBLE, new FieldDeclarator("mass")), + new FieldDeclaration(FieldDeclaration.FLAG_PRIVATE | FieldDeclaration.FLAG_FINAL, PrimitiveType.TYPE_DOUBLE, new FieldDeclarator("radius")), + new ConstructorDeclaration( + 0, + new FormalParameters( + new FormalParameter(PrimitiveType.TYPE_DOUBLE, "mass"), + new FormalParameter(PrimitiveType.TYPE_DOUBLE, "radius") + ), + "(DD)V", + new Statements( + new ExpressionStatement(new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D"), + "=", + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "mass"), + 16 + )), + new ExpressionStatement(new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), + "=", + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "radius"), + 16 + )) + ) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PRIVATE, + "mass", + PrimitiveType.TYPE_DOUBLE, + "()D", + new ReturnExpressionStatement(new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D")) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PRIVATE, + "radius", + PrimitiveType.TYPE_DOUBLE, + "()D", + new ReturnExpressionStatement(new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D")) + ), + new FieldDeclaration( + FieldDeclaration.FLAG_PUBLIC | FieldDeclaration.FLAG_STATIC | FieldDeclaration.FLAG_FINAL, + PrimitiveType.TYPE_DOUBLE, + new FieldDeclarator("G", new ExpressionVariableInitializer(new DoubleConstantExpression(6.67300E-11))) + ), + new MethodDeclaration( + 0, + "surfaceGravity", + PrimitiveType.TYPE_DOUBLE, + "()D", + new ReturnExpressionStatement( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "G", "D"), + "*", + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D"), + "/", + new ParenthesesExpression(new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), + "*", + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), + 4 + )), + 4 + ), + 4 + ) + ) + ), + new MethodDeclaration( + 0, + "surfaceWeight", + PrimitiveType.TYPE_DOUBLE, + new FormalParameter(PrimitiveType.TYPE_DOUBLE, "otherMass"), + "(D)D", + new ReturnExpressionStatement( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "otherMass"), + "*", + new MethodInvocationExpression( + PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "surfaceGravity", "()D" + ), + 4 + ) + ) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, + "surfaceWeight", + PrimitiveType.TYPE_VOID, + new FormalParameter(arrayOfStringType, "args"), + "([Ljava/lan/String;)V", + new Statements( + new IfStatement( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_BOOLEAN, + new LengthExpression(new LocalVariableReferenceExpression(arrayOfStringType, "args")), + "!=", + new IntegerConstantExpression(PrimitiveType.TYPE_INT, 1), + 9 + ), + new Statements( + new ExpressionStatement(new MethodInvocationExpression( + PrimitiveType.TYPE_VOID, + new FieldReferenceExpression( + printStreamType, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "out", + "Ljava/io/PrintStream;" + ), + "java/io/PrintStream", + "println", + "(Ljava/lang/String;)V", + new StringConstantExpression("Usage: java Planet ") + )), + new ExpressionStatement(new MethodInvocationExpression( + PrimitiveType.TYPE_VOID, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "exit", + "(I)V", + new IntegerConstantExpression(PrimitiveType.TYPE_INT, -1) + )) + ) + ), + new LocalVariableDeclarationStatement( + PrimitiveType.TYPE_DOUBLE, + new LocalVariableDeclarator("earthWeight", new ExpressionVariableInitializer( + new MethodInvocationExpression( + PrimitiveType.TYPE_DOUBLE, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/Double", "java.lang.Double", "Double")), + "java/lang/Double", + "parseDouble", + "(Ljava/lang/String;)D", + new ArrayExpression( + new LocalVariableReferenceExpression(arrayOfStringType, "args"), + new IntegerConstantExpression(PrimitiveType.TYPE_INT, 0) + ) + ) + )) + ), + new LocalVariableDeclarationStatement( + PrimitiveType.TYPE_DOUBLE, + new LocalVariableDeclarator("mass", new ExpressionVariableInitializer( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "earthWeight"), + "/", + new MethodInvocationExpression( + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression( + planetType, + new ObjectTypeReferenceExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")), + "org/jd/core/v1/service/test/Planet", + "EARTH", + "org/jd/core/v1/service/test/Planet"), + "org/jd/core/v1/service/test/Planet", + "surfaceGravity", + "()D" + ), + 4 + ) + )) + ), + new ForEachStatement( + planetType, + "p", + new MethodInvocationExpression( + planetType, + new ObjectTypeReferenceExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")), + "org/jd/core/v1/service/test/Planet", + "values", + "()[Lorg/jd/core/v1/service/test/Planet;"), + new ExpressionStatement(new MethodInvocationExpression( + PrimitiveType.TYPE_VOID, + new FieldReferenceExpression( + printStreamType, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "out", + "Ljava/io/PrintStream;" + ), + "java/io/PrintStream", + "printf", + "(Ljava/lang/String;[Ljava/lang/Object;)V", + new Expressions( + new StringConstantExpression("Your weight on %s is %f%n"), + new LocalVariableReferenceExpression(planetType, "p"), + new MethodInvocationExpression( + PrimitiveType.TYPE_DOUBLE, + new LocalVariableReferenceExpression(planetType, "p"), + "org/jd/core/v1/service/test/Planet", + "surfaceWeight", + "(D)D", + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "mass") + ) + ) + )) + ) + ) + ) + ) + ) + ) + ); + + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Message message = new Message(compilationUnit); + + message.setHeader("mainInternalTypeName", "org/jd/core/v1/service/test/Planet"); + message.setHeader("loader", new NopLoader()); + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + fragmenter.process(message); + layouter.process(message); + //tokenizer.process(message); + new JavaFragmentToTokenProcessor().process(message); + writer.process(message); + + String source = printer.toString(); + + System.out.println("- - - - - - - - "); + System.out.print(source); + System.out.println("- - - - - - - - "); + } + + @Test + public void testSwitch() throws Exception { + CompilationUnit compilationUnit = new CompilationUnit( + new ClassDeclaration( + ClassDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/SwitchTest", + "SwitchTest", + new BodyDeclaration( + "org/jd/core/v1/service/test/SwitchTest", + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, + "translate", + PrimitiveType.TYPE_INT, + new FormalParameter(PrimitiveType.TYPE_INT, "i"), + "(I)Ljava/lang/String;", + new SwitchStatement( + new LocalVariableReferenceExpression(PrimitiveType.TYPE_INT, "i"), + Arrays.asList( + (SwitchStatement.Block)new SwitchStatement.LabelBlock( + new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 0)), + new Statements( + new LocalVariableDeclarationStatement( + ObjectType.TYPE_STRING, + new LocalVariableDeclarator("zero", new ExpressionVariableInitializer(new StringConstantExpression("zero"))) + ), + new ReturnExpressionStatement(new LocalVariableReferenceExpression(ObjectType.TYPE_STRING, "zero")) + ) + ), + new SwitchStatement.MultiLabelsBlock( + Arrays.asList( + (SwitchStatement.Label)new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 1)), + new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 2)) + ), + new ReturnExpressionStatement(new StringConstantExpression("one or two")) + ), + new SwitchStatement.LabelBlock( + SwitchStatement.DEFAULT_LABEL, + new ReturnExpressionStatement(new StringConstantExpression("other")) + ) + ) + ) + ) + ) + ) + ); + + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Message message = new Message(compilationUnit); + + message.setHeader("mainInternalTypeName", "org/jd/core/v1/service/test/SwitchTest"); + message.setHeader("loader", new NopLoader()); + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + System.out.println("- - - - - - - - "); + System.out.print(source); + System.out.println("- - - - - - - - "); + + Assert.assertTrue(source.indexOf("switch (i)") != -1); + } + + @Test + public void testBridgeAndSyntheticAttributes() throws Exception { + CompilationUnit compilationUnit = new CompilationUnit( + new ClassDeclaration( + ClassDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/SyntheticAttributeTest", + "SyntheticAttributeTest", + new BodyDeclaration( + "org/jd/core/v1/service/test/SyntheticAttributeTest", + new MemberDeclarations( + new FieldDeclaration( + FieldDeclaration.FLAG_PUBLIC|FieldDeclaration.FLAG_BRIDGE, + PrimitiveType.TYPE_INT, + new FieldDeclarator("i") + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC|MethodDeclaration.FLAG_BRIDGE, + "testBridgeAttribute", + PrimitiveType.TYPE_VOID, + "()V" + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC|MethodDeclaration.FLAG_SYNTHETIC, + "testSyntheticAttribute", + PrimitiveType.TYPE_VOID, + "()V" + ) + ) + ) + ) + ); + + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + Message message = new Message(compilationUnit); + + message.setHeader("mainInternalTypeName", "org/jd/core/v1/service/test/SyntheticAttributeTest"); + message.setHeader("loader", new NopLoader()); + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + System.out.println("- - - - - - - - "); + System.out.print(source); + System.out.println("- - - - - - - - "); + + Assert.assertTrue(source.indexOf("/* bridge */") == -1); + Assert.assertTrue(source.indexOf("/* synthetic */") == -1); + } +} diff --git a/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java b/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java new file mode 100644 index 00000000..458cd923 --- /dev/null +++ b/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.jd.core.v1.services.tokenizer.javafragmenttotoken.TestTokenizeJavaFragmentProcessor; +import org.jd.core.v1.util.PatternMaker; +import org.junit.Assert; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class LayoutFragmentProcessorTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk118Basic() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 183: 183]") != -1); + } + + @Test + public void testJdk131TryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.3.1.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 902: 902]") != -1); + } + + @Test + public void testTryCatchFinally() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 902: 902]") != -1); + } + + @Test + public void testAnonymousClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AnonymousClass"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 111: 111]") != -1); + + assertTrue(source.indexOf("} ;") == -1); + } + + @Test + public void testOuterClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/OuterClass"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 182: 182]") != -1); + } + + @Test + public void testEnumClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Enum"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("NEPTUNE(1.024E26D, 2.4746E7D);") != -1); + assertTrue(source.indexOf("public static final double G = 6.673E-11D;") != -1); + } + + @Test + public void testAnnotationQuality() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/annotation/Quality"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("[ 9: 0] }") != -1); + } + + @Test + public void testJdk170Array() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Array"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + Assert.assertTrue(source.matches(PatternMaker.make("[ 30: 30]", "int[][] ia", "0, 1, 2"))); + + assertTrue(source.indexOf("[ 75: 75]") != -1); + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java new file mode 100644 index 00000000..88e8101a --- /dev/null +++ b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import org.jd.core.v1.model.classfile.ClassFile; +import org.jd.core.v1.model.classfile.Method; +import org.jd.core.v1.model.javasyntax.declaration.FieldDeclarator; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.MergeMembersUtil; +import org.jd.core.v1.util.DefaultList; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +@SuppressWarnings("unchecked") +public class MergeMembersUtilTest { + + @Test + public void testEmptyResult() throws Exception { + DefaultList methods = newMethods(); + + List result = MergeMembersUtil.merge(null, methods, null); + + Assert.assertEquals(methods, result); + } + + @Test + public void testMergeFieldsAndMethods() throws Exception { + DefaultList fields = newFields(); + DefaultList methods = newMethods(); + + List result = MergeMembersUtil.merge(fields, methods, null); + + Assert.assertEquals(fields.size() + methods.size(), result.size()); + Assert.assertEquals(10, result.get(3).getFirstLineNumber()); + Assert.assertEquals(11, result.get(4).getFirstLineNumber()); + Assert.assertEquals(20, result.get(9).getFirstLineNumber()); + Assert.assertEquals(21, result.get(10).getFirstLineNumber()); + Assert.assertEquals(30, result.get(11).getFirstLineNumber()); + } + + @Test + public void testMergeFieldsMethodsAndInnerTypes_0() throws Exception { + DefaultList fields = newFields(); + DefaultList methods = newMethods(); + DefaultList innerTypes = newInnerTypes(0); + + List result = MergeMembersUtil.merge(fields, methods, innerTypes); + + Assert.assertEquals(fields.size() + methods.size() + innerTypes.size(), result.size()); + Assert.assertEquals(10, result.get(3).getFirstLineNumber()); + Assert.assertEquals(11, result.get(4).getFirstLineNumber()); + Assert.assertEquals(20, result.get(9).getFirstLineNumber()); + Assert.assertEquals(21, result.get(10).getFirstLineNumber()); + Assert.assertEquals(30, result.get(11).getFirstLineNumber()); + Assert.assertEquals( 0, result.get(12).getFirstLineNumber()); + Assert.assertEquals( 0, result.get(20).getFirstLineNumber()); + } + + @Test + public void testMergeFieldsMethodsAndInnerTypes_25() throws Exception { + DefaultList fields = newFields(); + DefaultList methods = newMethods(); + DefaultList innerTypes = newInnerTypes(25); + + List result = MergeMembersUtil.merge(fields, methods, innerTypes); + + Assert.assertEquals(fields.size() + methods.size() + innerTypes.size(), result.size()); + Assert.assertEquals(10, result.get(3).getFirstLineNumber()); + Assert.assertEquals(11, result.get(4).getFirstLineNumber()); + Assert.assertEquals(20, result.get(9).getFirstLineNumber()); + Assert.assertEquals(21, result.get(10).getFirstLineNumber()); + Assert.assertEquals(25, result.get(11).getFirstLineNumber()); + Assert.assertEquals(30, result.get(12).getFirstLineNumber()); + } + + @Test + public void testMergeFields() throws Exception { + ClassFileFieldDeclaration a = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a")); + ClassFileFieldDeclaration b = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b")); + ClassFileFieldDeclaration c = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c")); + + List fields = Arrays.asList(a, b, c); + + List result = MergeMembersUtil.merge(fields, null, null); + + Assert.assertEquals(fields.size(), result.size()); + Assert.assertEquals(a, result.get(0)); + Assert.assertEquals(b, result.get(1)); + Assert.assertEquals(c, result.get(2)); + } + + @Test + public void testMergeAscendantSortedFields1() throws Exception { + ClassFileFieldDeclaration a = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"), 1); + ClassFileFieldDeclaration b = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 2); + ClassFileFieldDeclaration c = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"), 3); + + List fields = Arrays.asList(a, b, c); + + List result = MergeMembersUtil.merge(fields, null, null); + + Assert.assertEquals(fields.size(), result.size()); + Assert.assertEquals(a, result.get(0)); + Assert.assertEquals(b, result.get(1)); + Assert.assertEquals(c, result.get(2)); + } + + @Test + public void testMergeAscendantSortedFields2() throws Exception { + ClassFileFieldDeclaration a = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a")); + ClassFileFieldDeclaration b = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 1); + ClassFileFieldDeclaration c = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c")); + ClassFileFieldDeclaration d = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), 2); + ClassFileFieldDeclaration e = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("e"), 3); + ClassFileFieldDeclaration f = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("f")); + + List fields = Arrays.asList(a, b, c, d, e, f); + + List result = MergeMembersUtil.merge(fields, null, null); + + Assert.assertEquals(fields.size(), result.size()); + Assert.assertEquals(a, result.get(0)); + Assert.assertEquals(b, result.get(1)); + Assert.assertEquals(c, result.get(2)); + Assert.assertEquals(d, result.get(3)); + Assert.assertEquals(e, result.get(4)); + Assert.assertEquals(f, result.get(5)); + } + + @Test + public void testMergeDescendantSortedFields1() throws Exception { + ClassFileFieldDeclaration a = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"), 3); + ClassFileFieldDeclaration b = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 2); + ClassFileFieldDeclaration c = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"), 1); + + List fields = Arrays.asList(a, b, c); + + List result = MergeMembersUtil.merge(fields, null, null); + + Assert.assertEquals(fields.size(), result.size()); + Assert.assertEquals(c, result.get(0)); + Assert.assertEquals(b, result.get(1)); + Assert.assertEquals(a, result.get(2)); + } + + @Test + public void testMergeDescendantSortedFields2() throws Exception { + ClassFileFieldDeclaration a = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a")); + ClassFileFieldDeclaration b = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 3); + ClassFileFieldDeclaration c = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c")); + ClassFileFieldDeclaration d = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), 2); + ClassFileFieldDeclaration e = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("e"), 1); + ClassFileFieldDeclaration f = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("f")); + + List fields = Arrays.asList(a, b, c, d, e, f); + + List result = MergeMembersUtil.merge(fields, null, null); + + Assert.assertEquals(fields.size(), result.size()); + Assert.assertEquals(f, result.get(0)); + Assert.assertEquals(e, result.get(1)); + Assert.assertEquals(d, result.get(2)); + Assert.assertEquals(c, result.get(3)); + Assert.assertEquals(b, result.get(4)); + Assert.assertEquals(a, result.get(5)); + } + + @Test + public void testMergeUnsortedFields1() throws Exception { + ClassFileFieldDeclaration a = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"), 3); + ClassFileFieldDeclaration b = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 1); + ClassFileFieldDeclaration c = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"), 2); + + List fields = Arrays.asList(a, b, c); + + List result = MergeMembersUtil.merge(fields, null, null); + + Assert.assertEquals(fields.size(), result.size()); + Assert.assertEquals(b, result.get(0)); + Assert.assertEquals(c, result.get(1)); + Assert.assertEquals(a, result.get(2)); + } + + @Test + public void testMergeUnsortedFields2() throws Exception { + ClassFileFieldDeclaration a = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a")); + ClassFileFieldDeclaration b = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"), 3); + ClassFileFieldDeclaration c = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c")); + ClassFileFieldDeclaration d = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), 1); + ClassFileFieldDeclaration e = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("e"), 2); + ClassFileFieldDeclaration f = new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("f")); + + List fields = Arrays.asList(a, b, c, d, e, f); + + List result = MergeMembersUtil.merge(fields, null, null); + + Assert.assertEquals(fields.size(), result.size()); + Assert.assertEquals(d, result.get(0)); + Assert.assertEquals(e, result.get(1)); + Assert.assertEquals(b, result.get(2)); + Assert.assertEquals(a, result.get(3)); + Assert.assertEquals(c, result.get(4)); + Assert.assertEquals(f, result.get(5)); + } + + protected DefaultList newFields() { + DefaultList fields = new DefaultList<>(); + + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("a"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("b"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("c"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), 10)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("e"), 11)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("f"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("g"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("h"), 30)); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("i"))); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("j"))); + + return fields; + } + + protected DefaultList newMethods() { + DefaultList methods = new DefaultList<>(); + ClassFile classFile = null; + Method method = new Method(0, "method", "()V", null, null); + + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "a", PrimitiveType.TYPE_VOID, null)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "b", PrimitiveType.TYPE_VOID, null)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "c", PrimitiveType.TYPE_VOID, null, 20)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "d", PrimitiveType.TYPE_VOID, null, 21)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "e", PrimitiveType.TYPE_VOID, null)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "f", PrimitiveType.TYPE_VOID, null)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "g", PrimitiveType.TYPE_VOID, null, 40)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "h", PrimitiveType.TYPE_VOID, null)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "i", PrimitiveType.TYPE_VOID, null)); + methods.add(new ClassFileMethodDeclaration(null, classFile, method, "j", PrimitiveType.TYPE_VOID, null)); + + return methods; + } + + protected DefaultList newInnerTypes(int lineNumber) { + DefaultList innerTypes = new DefaultList<>(); + + DefaultList fields = new DefaultList<>(); + fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), lineNumber)); + + ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration("A"); + bodyDeclaration.setFieldDeclarations(fields); + + innerTypes.add(new ClassFileClassDeclaration(null, 0, "A", "A", null, null, null, bodyDeclaration)); + + return innerTypes; + } +} diff --git a/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java b/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java new file mode 100644 index 00000000..ba700389 --- /dev/null +++ b/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.junit.Test; + +import java.io.InputStream; + +public class ObjectTypeMakerTest extends TestCase { + + @Test + public void testOuterClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("org/jd/core/test/OuterClass"); + + assertEquals("org/jd/core/test/OuterClass", ot.getInternalName()); + assertEquals("org.jd.core.test.OuterClass", ot.getQualifiedName()); + assertEquals("OuterClass", ot.getName()); + } + + @Test + public void testOuterClass$InnerClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("org/jd/core/test/OuterClass$InnerClass"); + + assertEquals("org/jd/core/test/OuterClass$InnerClass", ot.getInternalName()); + assertEquals("org.jd.core.test.OuterClass.InnerClass", ot.getQualifiedName()); + assertEquals("InnerClass", ot.getName()); + } + + @Test + public void testOuterClass$StaticInnerClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("org/jd/core/test/OuterClass$StaticInnerClass"); + + assertEquals("org/jd/core/test/OuterClass$StaticInnerClass", ot.getInternalName()); + assertEquals("org.jd.core.test.OuterClass.StaticInnerClass", ot.getQualifiedName()); + assertEquals("StaticInnerClass", ot.getName()); + } + + @Test + public void testOuterClass$1() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("org/jd/core/test/OuterClass$1"); + + assertEquals("org/jd/core/test/OuterClass$1", ot.getInternalName()); + assertNull(ot.getQualifiedName()); + assertNull(ot.getName()); + } + + @Test + public void testOuterClass$1LocalClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("org/jd/core/test/OuterClass$1LocalClass"); + + assertEquals("org/jd/core/test/OuterClass$1LocalClass", ot.getInternalName()); + assertNull(ot.getQualifiedName()); + assertEquals("LocalClass", ot.getName()); + } + + @Test + public void testThread() throws Exception { + ClassPathLoader loader = new ClassPathLoader(); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("java/lang/Thread"); + + assertEquals("java/lang/Thread", ot.getInternalName()); + assertEquals("java.lang.Thread", ot.getQualifiedName()); + assertEquals("Thread", ot.getName()); + } + + @Test + public void testThreadState() throws Exception { + ClassPathLoader loader = new ClassPathLoader(); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("java/lang/Thread$State"); + + assertEquals("java/lang/Thread$State", ot.getInternalName()); + assertEquals("java.lang.Thread.State", ot.getQualifiedName()); + assertEquals("State", ot.getName()); + } + + @Test + public void testUnknownClass() throws Exception { + ClassPathLoader loader = new ClassPathLoader(); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("org/unknown/Class"); + + assertEquals("org/unknown/Class", ot.getInternalName()); + assertEquals("org.unknown.Class", ot.getQualifiedName()); + assertEquals("Class", ot.getName()); + } + + @Test + public void testUnknownInnerClass() throws Exception { + ClassPathLoader loader = new ClassPathLoader(); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType ot = maker.make("org/unknown/Class$InnerClass"); + + assertEquals("org/unknown/Class$InnerClass", ot.getInternalName()); + assertEquals("org.unknown.Class.InnerClass", ot.getQualifiedName()); + assertEquals("InnerClass", ot.getName()); + } + + @Test + public void testListIsAssignableFromArrayList() throws Exception { + ClassPathLoader loader = new ClassPathLoader(); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType parent = maker.make("java/util/List"); + ObjectType child = maker.make("java/util/ArrayList"); + + assertNotNull(parent); + assertNotNull(child); + assertTrue(maker.isAssignable(parent, child)); + } + + @Test + public void testClassIsAssignableFromObject() throws Exception { + ClassPathLoader loader = new ClassPathLoader(); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType parent = maker.make("java/lang/Class"); + ObjectType child = maker.make("java/lang/Object"); + + assertNotNull(parent); + assertNotNull(child); + assertFalse(maker.isAssignable(parent, child)); + } + + @Test + public void testObjectIsAssignableFromSafeNumberComparator() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType parent = maker.make("java/lang/Object"); + ObjectType child = maker.make("org/jd/core/test/OuterClass$SafeNumberComparator"); + + assertNotNull(parent); + assertNotNull(child); + assertTrue(maker.isAssignable(parent, child)); + } + + @Test + public void testComparatorIsAssignableFromSafeNumberComparator() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType parent = maker.make("java/util/Comparator"); + ObjectType child = maker.make("org/jd/core/test/OuterClass$SafeNumberComparator"); + + assertNotNull(parent); + assertNotNull(child); + assertTrue(maker.isAssignable(parent, child)); + } + + @Test + public void testNumberComparatorIsAssignableFromSafeNumberComparator() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType parent = maker.make("org/jd/core/test/OuterClass$NumberComparator"); + ObjectType child = maker.make("org/jd/core/test/OuterClass$SafeNumberComparator"); + + assertNotNull(parent); + assertNotNull(child); + assertTrue(maker.isAssignable(parent, child)); + } + + @Test + public void testOuterClassIsAssignableFromSimpleClass() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker maker = new ObjectTypeMaker(loader); + ObjectType parent = maker.make("org/jd/core/test/OuterClass"); + ObjectType child = maker.make("org/jd/core/test/SimpleClass"); + + assertNotNull(parent); + assertNotNull(child); + assertFalse(maker.isAssignable(parent, child)); + } +} diff --git a/src/test/java/org/jd/core/v1/SignatureParserTest.java b/src/test/java/org/jd/core/v1/SignatureParserTest.java new file mode 100644 index 00000000..5e5b55ab --- /dev/null +++ b/src/test/java/org/jd/core/v1/SignatureParserTest.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.classfile.ClassFile; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.services.javasyntax.type.visitor.PrintTypeVisitor; +import org.junit.Assert; +import org.junit.Test; + +import java.io.InputStream; + +public class SignatureParserTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + + @Test + public void testAnnotatedClass() throws Exception { + PrintTypeVisitor visitor = new PrintTypeVisitor(); + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker factory = new ObjectTypeMaker(loader); + SignatureParser parser = new SignatureParser(factory); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/AnnotatedClass"); + message.setHeader("loader", loader); + + deserializer.process(message); + + ClassFile classFile = message.getBody(); + + // Check type + SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + + // Check type parameterTypes + assertNull(typeTypes.typeParameters); + + // Check super type + assertNotNull(typeTypes.superType); + visitor.reset(); + typeTypes.superType.accept(visitor); + String source = visitor.toString(); + + Assert.assertEquals("java.util.ArrayList", source); + + // Check interfaces + assertNotNull(typeTypes.interfaces); + visitor.reset(); + typeTypes.interfaces.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.io.Serializable, java.lang.Cloneable", source); + + // Check field 'list1' + // public List> list1 + Type type = parser.parseFieldSignature(classFile.getFields()[0]); + visitor.reset(); + type.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("boolean", source); + + // Check method 'add' + // public int add(int i1, int i2) + SignatureParser.MethodTypes methodTypes = parser.parseMethodSignature(classFile.getMethods()[1]); + + // Check type parameterTypes + assertNull(methodTypes.typeParameters); + + // Check parameterTypes + assertNotNull(methodTypes.parameters); + assertEquals(2, methodTypes.parameters.size()); + + type = methodTypes.parameters.get(0); + visitor.reset(); + type.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("int", source); + + // Check return type + assertNotNull(methodTypes.returned); + + visitor.reset(); + methodTypes.returned.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("int", source); + + // Check exceptions + assertNull(methodTypes.exceptions); + + // Check method 'ping' + // public void ping(String host) throws UnknownHostException, UnsatisfiedLinkError + methodTypes = parser.parseMethodSignature(classFile.getMethods()[2]); + + // Check type parameterTypes + assertNull(methodTypes.typeParameters); + + // Check parameterTypes + assertNotNull(methodTypes.parameters); + assertEquals(3, methodTypes.parameters.size()); + + type = methodTypes.parameters.get(1); + visitor.reset(); + type.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.lang.String", source); + + // Check return type + assertNotNull(methodTypes.returned); + + visitor.reset(); + methodTypes.returned.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("void", source); + + // Check exceptions + assertNotNull(methodTypes.exceptions); + + visitor.reset(); + methodTypes.exceptions.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.net.UnknownHostException, java.lang.UnsatisfiedLinkError", source); + } + + @Test + public void testGenericClass() throws Exception { + PrintTypeVisitor visitor = new PrintTypeVisitor(); + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker factory = new ObjectTypeMaker(loader); + SignatureParser parser = new SignatureParser(factory); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/GenericClass"); + message.setHeader("loader", loader); + + deserializer.process(message); + + ClassFile classFile = message.getBody(); + + // Check type + SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + + // Check type parameterTypes + // See "org.jd.core.test.resources.java.Generic" + // T1:Ljava/lang/Object; + // T2:Ljava/lang/Object; + // T3:Lorg/jd/core/v1/test/resources/java/AnnotatedClass; + // T4::Ljava/io/Serializable; + // T5::Ljava/io/Serializable;:Ljava/lang/Comparable; + // T6:Lorg/jd/core/v1/test/resources/java/AnnotatedClass;:Ljava/io/Serializable;:Ljava/lang/Comparable; + // T7::Ljava/util/Map<**>; + // T8::Ljava/util/Map<+Ljava/lang/Number;-Ljava/io/Serializable;>; + // T9:TT8; + assertNotNull(typeTypes.typeParameters); + typeTypes.typeParameters.accept(visitor); + + String source = visitor.toString(); + String expected = + "T1, " + + "T2, " + + "T3 extends org.jd.core.test.AnnotatedClass, " + + "T4 extends java.io.Serializable, " + + "T5 extends java.io.Serializable & java.lang.Comparable, " + + "T6 extends org.jd.core.test.AnnotatedClass & java.io.Serializable & java.lang.Comparable, " + + "T7 extends java.util.Map, " + + "T8 extends java.util.Map, " + + "T9 extends T8"; + + Assert.assertEquals(expected, source); + + // Check super type + assertNotNull(typeTypes.superType); + visitor.reset(); + typeTypes.superType.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.util.ArrayList", source); + + // Check interfaces + assertNotNull(typeTypes.interfaces); + visitor.reset(); + typeTypes.interfaces.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.io.Serializable, java.lang.Comparable", source); + + // Check field 'list1' + // public List> list1 + Type type = parser.parseFieldSignature(classFile.getFields()[0]); + visitor.reset(); + type.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.util.List>", source); + + // Check method 'copy2' + // public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException + SignatureParser.MethodTypes methodTypes = parser.parseMethodSignature(classFile.getMethods()[3]); + + // Check type parameterTypes + assertNotNull(methodTypes.typeParameters); + visitor.reset(); + methodTypes.typeParameters.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("T, S extends T", source); + + // Check parameterTypes + assertNotNull(methodTypes.parameters); + assertEquals(2, methodTypes.parameters.size()); + + type = methodTypes.parameters.get(0); + visitor.reset(); + type.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.util.List", source); + + // Check return type + assertNotNull(methodTypes.returned); + + visitor.reset(); + methodTypes.returned.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.util.List", source); + + // Check exceptions + assertNotNull(methodTypes.exceptions); + + visitor.reset(); + methodTypes.exceptions.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.security.InvalidParameterException, java.lang.ClassCastException", source); + + // Check method 'print' + // public List print(List list) throws InvalidParameterException, T2 + methodTypes = parser.parseMethodSignature(classFile.getMethods()[4]); + + // Check type parameterTypes + assertNotNull(methodTypes.typeParameters); + visitor.reset(); + methodTypes.typeParameters.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("T1, T2 extends java.lang.Exception", source); + + // Check parameterTypes + assertNotNull(methodTypes.parameters); + assertEquals(1, methodTypes.parameters.size()); + + type = methodTypes.parameters.get(0); + visitor.reset(); + type.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.util.List", source); + + // Check return type + assertNotNull(methodTypes.returned); + + visitor.reset(); + methodTypes.returned.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("java.util.List", source); + + // Check exceptions + assertNotNull(methodTypes.exceptions); + + visitor.reset(); + methodTypes.exceptions.accept(visitor); + source = visitor.toString(); + + Assert.assertEquals("T2, java.security.InvalidParameterException", source); + } + + @Test + public void testParseReturnedVoid() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker factory = new ObjectTypeMaker(loader); + SignatureParser parser = new SignatureParser(factory); + + Assert.assertEquals(parser.parseReturnedType("()V"), PrimitiveType.TYPE_VOID); + } + + @Test + public void testParseReturnedPrimitiveType() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker factory = new ObjectTypeMaker(loader); + SignatureParser parser = new SignatureParser(factory); + + Assert.assertEquals(parser.parseReturnedType("()Z"), PrimitiveType.TYPE_BOOLEAN); + } + + @Test + public void testParseReturnedStringType() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + ZipLoader loader = new ZipLoader(is); + ObjectTypeMaker factory = new ObjectTypeMaker(loader); + SignatureParser parser = new SignatureParser(factory); + + Assert.assertEquals(parser.parseReturnedType("()Ljava/lang/String;"), ObjectType.TYPE_STRING); + } + + +} \ No newline at end of file diff --git a/src/test/java/org/jd/core/v1/TypeTest.java b/src/test/java/org/jd/core/v1/TypeTest.java new file mode 100644 index 00000000..3fc26004 --- /dev/null +++ b/src/test/java/org/jd/core/v1/TypeTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.services.javasyntax.type.visitor.PrintTypeVisitor; +import org.junit.Test; + +import java.util.Arrays; + +public class TypeTest extends TestCase { + @Test + public void testSimpleClassOrInterfaceType() throws Exception { + Type scoit = new ObjectType("org/project/Test", "org.project.Test", "Test"); + PrintTypeVisitor visitor = new PrintTypeVisitor(); + + scoit.accept(visitor); + + String source = visitor.toString(); + + printSource(source); + + assertEquals("org.project.Test", source); + } + + @Test + public void testSimpleClassOrInterfaceType2() throws Exception { + Type scoit1 = new ObjectType("org/project/Test", "org.project.Test", "Test"); + Type scoit2 = new ObjectType( + "org/project/OtherTest", "org.project.OtherTest", "OtherTest", + new ArrayTypeArguments( + Arrays.asList( + scoit1, + new UnknownTypeArgument(), + new WildcardSuperTypeArgument(scoit1), + new WildcardExtendsTypeArgument(scoit1) + ) + ) + ); + + PrintTypeVisitor visitor = new PrintTypeVisitor(); + + scoit2.accept(visitor); + + String source = visitor.toString(); + + printSource(source); + + assertEquals("org.project.OtherTest", source); + } + + @Test + public void testDiamond() throws Exception { + Type scoit = new ObjectType("org/project/Test", "org.project.Test", "Test", DiamondTypeArgument.DIAMOND); + + PrintTypeVisitor visitor = new PrintTypeVisitor(); + + scoit.accept(visitor); + + String source = visitor.toString(); + + printSource(source); + + assertEquals("org.project.Test<>", source); + } + + @Test + public void testInnerClass() throws Exception { + Type scoit = new InnerObjectType("org/project/Test$InnerTest", "org.project.Test.InnerTest", "InnerTest", + new ObjectType("org/project/Test", "org.project.Test", "Test")); + + PrintTypeVisitor visitor = new PrintTypeVisitor(); + + scoit.accept(visitor); + + String source = visitor.toString(); + + printSource(source); + + assertEquals("org.project.Test.InnerTest", source); + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} \ No newline at end of file diff --git a/src/test/java/org/jd/core/v1/UpdateSpacerBetweenMovableBlocksVisitorTest.java b/src/test/java/org/jd/core/v1/UpdateSpacerBetweenMovableBlocksVisitorTest.java new file mode 100644 index 00000000..163c745e --- /dev/null +++ b/src/test/java/org/jd/core/v1/UpdateSpacerBetweenMovableBlocksVisitorTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.model.fragment.FlexibleFragment; +import org.jd.core.v1.model.fragment.Fragment; +import org.jd.core.v1.model.fragment.SpacerBetweenMovableBlocksFragment; +import org.jd.core.v1.service.layouter.visitor.UpdateSpacerBetweenMovableBlocksVisitor; +import org.jd.core.v1.util.DefaultList; +import org.junit.Test; + +import static org.jd.core.v1.model.javafragment.EndMovableJavaBlockFragment.END_MOVABLE_BLOCK; +import static org.jd.core.v1.model.javafragment.StartMovableJavaBlockFragment.*; + + +@SuppressWarnings("unchecked") +public class UpdateSpacerBetweenMovableBlocksVisitorTest extends TestCase { + @Test + public void test() { + UpdateSpacerBetweenMovableBlocksVisitor visitor = new UpdateSpacerBetweenMovableBlocksVisitor(); + DefaultList fragments = new DefaultList<>(); + FlexibleFragment spacer1, spacer2, spacer3, spacer4, spacer5, spacer6, spacer7; + + fragments.add(START_MOVABLE_TYPE_BLOCK); + fragments.add(START_MOVABLE_FIELD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + fragments.add(spacer1 = new SpacerBetweenMovableBlocksFragment(0, 2, Integer.MAX_VALUE, 7, "Spacer 1")); + fragments.add(START_MOVABLE_FIELD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + + fragments.add(spacer2 = new SpacerBetweenMovableBlocksFragment(0, 2, Integer.MAX_VALUE, 7, "Spacer 2")); + + fragments.add(START_MOVABLE_METHOD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + + fragments.add(spacer3 = new SpacerBetweenMovableBlocksFragment(0, 2, Integer.MAX_VALUE, 7, "Spacer 3")); + + fragments.add(START_MOVABLE_FIELD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + + fragments.add(spacer4 = new SpacerBetweenMovableBlocksFragment(0, 2, Integer.MAX_VALUE, 7, "Spacer 4")); + + fragments.add(START_MOVABLE_TYPE_BLOCK); + fragments.add(START_MOVABLE_FIELD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + fragments.add(spacer5 = new SpacerBetweenMovableBlocksFragment(0, 2, Integer.MAX_VALUE, 7, "Spacer 5")); + fragments.add(START_MOVABLE_FIELD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + + fragments.add(spacer6 = new SpacerBetweenMovableBlocksFragment(0, 2, Integer.MAX_VALUE, 7, "Spacer 6")); + + fragments.add(START_MOVABLE_METHOD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + + fragments.add(spacer7 = new SpacerBetweenMovableBlocksFragment(0, 2, Integer.MAX_VALUE, 7, "Spacer 7")); + + fragments.add(START_MOVABLE_METHOD_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + fragments.add(END_MOVABLE_BLOCK); + + visitor.reset(); + + for (Fragment fragment : fragments) { + fragment.accept(visitor); + } + + assertTrue(spacer1.getInitialLineCount() == 1); + assertTrue(spacer2.getInitialLineCount() == 2); + assertTrue(spacer3.getInitialLineCount() == 2); + assertTrue(spacer4.getInitialLineCount() == 2); + assertTrue(spacer5.getInitialLineCount() == 1); + assertTrue(spacer6.getInitialLineCount() == 2); + assertTrue(spacer7.getInitialLineCount() == 2); + } +} \ No newline at end of file diff --git a/src/test/java/org/jd/core/v1/WriteTokenTest.java b/src/test/java/org/jd/core/v1/WriteTokenTest.java new file mode 100644 index 00000000..79a3cc5a --- /dev/null +++ b/src/test/java/org/jd/core/v1/WriteTokenTest.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.model.token.*; +import org.jd.core.v1.printer.PlainTextMetaPrinter; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.jd.core.v1.util.DefaultList; +import org.junit.Assert; +import org.junit.Test; + +public class WriteTokenTest { + + public static final KeywordToken PACKAGE = new KeywordToken("package"); + public static final KeywordToken IF = new KeywordToken("if"); + public static final KeywordToken IMPORT = new KeywordToken("import"); + public static final KeywordToken STATIC = new KeywordToken("static"); + public static final KeywordToken PUBLIC = new KeywordToken("public"); + public static final KeywordToken CLASS = new KeywordToken("class"); + public static final KeywordToken VOID = new KeywordToken("void"); + public static final KeywordToken INT = new KeywordToken("int"); + public static final KeywordToken BOOLEAN = new KeywordToken("boolean"); + public static final KeywordToken RETURN = new KeywordToken("return"); + public static final KeywordToken FALSE = new KeywordToken("false"); + public static final KeywordToken NULL = new KeywordToken("null"); + public static final KeywordToken NEW = new KeywordToken("new"); + + @Test + public void writeClassDeclaration() throws Exception { + DefaultList tokens = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + tokens.add(PACKAGE); + tokens.add(new TextToken(" org.jd.core.v1.service.test;")); + tokens.add(NewLineToken.NEWLINE_2); + + // import javasyntax.util.ArrayList;\n + tokens.add(IMPORT); + tokens.add(TextToken.SPACE); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/util/ArrayList", "java.util.ArrayList", null, null)); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_1); + + // import static org.junit.Assert.*;\n\n + tokens.add(IMPORT); + tokens.add(TextToken.SPACE); + tokens.add(STATIC); + tokens.add(TextToken.SPACE); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/junit/Assert/*", "org.junit.Assert.*", null, null)); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_2); + + // public class WriteTokenTest {\n + tokens.add(PUBLIC); + tokens.add(TextToken.SPACE); + tokens.add(CLASS); + tokens.add(TextToken.SPACE); + tokens.add(new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "WriteTokenTest", null)); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + + // public static void main(String[] args) {\n + tokens.add(PUBLIC); + tokens.add(TextToken.SPACE); + tokens.add(STATIC); + tokens.add(TextToken.SPACE); + tokens.add(VOID); + tokens.add(TextToken.SPACE); + tokens.add(new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "main", "([Ljava/lang/String;)V")); + tokens.add(TextToken.LEFTROUNDBRACKET); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/String", "String", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new TextToken("[] args) ")); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + + // if (args == null)\n + tokens.add(new LineNumberToken(8)); + tokens.add(IF); + tokens.add(new TextToken(" (args == ")); + tokens.add(NULL); + tokens.add(new TextToken(")")); + tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); + // return;\n + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(RETURN); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + + // int i = call(\n + // "aaaa",\n + // b,\n + // new Enumeration() {\n + // public boolean hasMoreElements() {\n + // return false;\n + // }\n + // public Object nextElement() {\n + // return null;\n + // }\n + // }, + // c);\n + tokens.add(new LineNumberToken(10)); + tokens.add(INT); + tokens.add(new TextToken(" i = ")); + tokens.add(new ReferenceToken(ReferenceToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "call", "(IILjava/util/Enumeration;I)V", "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(new LineNumberToken(11)); + tokens.add(new StringConstantToken("aaaa", "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(TextToken.COMMA); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(new LineNumberToken(12)); + tokens.add(new TextToken("b,")); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(new LineNumberToken(13)); + tokens.add(NEW); + tokens.add(TextToken.SPACE); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/util/Enumeration", "Enumeration", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new TextToken("() ")); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + // public boolean hasMoreElements()... + tokens.add(PUBLIC); + tokens.add(TextToken.SPACE); + tokens.add(BOOLEAN); + tokens.add(TextToken.SPACE); + tokens.add(new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest$1", "hasMoreElements", "()Z")); + tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); + tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + // return false; + tokens.add(new LineNumberToken(15)); + tokens.add(RETURN); + tokens.add(TextToken.SPACE); + tokens.add(FALSE); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + // public Object nextElement()... + tokens.add(PUBLIC); + tokens.add(TextToken.SPACE); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Object", "Object", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(TextToken.SPACE); + tokens.add(new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest$1", "nextElement", "()Ljava/lang/Object;")); + tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); + tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + // return null; + tokens.add(new LineNumberToken(18)); + tokens.add(RETURN); + tokens.add(TextToken.SPACE); + tokens.add(NULL); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(TextToken.COMMA); + tokens.add(NewLineToken.NEWLINE_1); + + tokens.add(new LineNumberToken(21)); + tokens.add(new TextToken("c")); + tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_1); + + // System.out.println(i); + tokens.add(new LineNumberToken(22)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/System", "System", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(TextToken.DOT); + tokens.add(new ReferenceToken(ReferenceToken.FIELD_FLAG, "java/lang/System", "out", "java/io/PrintStream", "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(TextToken.DOT); + tokens.add(new ReferenceToken(ReferenceToken.METHOD_FLAG, "java/io/PrintStream", "println", "(I)V", "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(TextToken.LEFTROUNDBRACKET); + tokens.add(new TextToken("i")); + tokens.add(TextToken.RIGHTROUNDBRACKET); + tokens.add(TextToken.SEMICOLON); + tokens.add(NewLineToken.NEWLINE_1); + + // }\n + tokens.add(EndBlockToken.END_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + + // } + tokens.add(EndBlockToken.END_BLOCK); + + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + WriteTokenProcessor writer = new WriteTokenProcessor(); + + Message message = new Message(tokens); + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 22); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + writer.process(message); + + String source = printer.toString(); + + System.out.println("- - - - - - - - "); + System.out.print(source); + System.out.println("- - - - - - - - "); + + String expected = + "[ 1: 0] package org.jd.core.v1.service.test;\n" + + "[ 2: 0] \n" + + "[ 3: 0] import java.util.ArrayList;\n" + + "[ 4: 0] import static org.junit.Assert.*;\n" + + "[ 5: 0] \n" + + "[ 6: 0] public class WriteTokenTest {\n" + + "[ 7: 0] public static void main(String[] args) {\n" + + "[ 8: 8] if (args == null)\n" + + "[ 9: 0] return;\n" + + "[ 10: 10] int i = call(\n" + + "[ 11: 11] \"aaaa\",\n" + + "[ 12: 12] b,\n" + + "[ 13: 13] new Enumeration() {\n" + + "[ 14: 0] public boolean hasMoreElements() {\n" + + "[ 15: 15] return false;\n" + + "[ 16: 0] }\n" + + "[ 17: 0] public Object nextElement() {\n" + + "[ 18: 18] return null;\n" + + "[ 19: 0] }\n" + + "[ 20: 0] },\n" + + "[ 21: 21] c);\n" + + "[ 22: 22] System.out.println(i);\n" + + "[ 23: 0] }\n" + + "[ 24: 0] }\n"; + + Assert.assertEquals(expected, source); + } + + + @Test + public void testComments() throws Exception { + DefaultList tokens = new DefaultList<>(); + + // package org.jd.core.v1.service.writer;\n\n + tokens.add(PACKAGE); + tokens.add(new TextToken(" org.jd.core.v1.service.test;")); + tokens.add(NewLineToken.NEWLINE_2); + + // /* Block comment */\n + tokens.add(StartMarkerToken.COMMENT); + tokens.add(new TextToken("/* Block comment */")); + tokens.add(EndMarkerToken.COMMENT); + tokens.add(NewLineToken.NEWLINE_1); + + // /* Javadoc comment */\n + tokens.add(StartMarkerToken.JAVADOC); + tokens.add(new TextToken("/** Javadoc comment */")); + tokens.add(EndMarkerToken.JAVADOC); + tokens.add(NewLineToken.NEWLINE_1); + + // public class WriteCommentTest {\n + tokens.add(PUBLIC); + tokens.add(TextToken.SPACE); + tokens.add(CLASS); + tokens.add(TextToken.SPACE); + tokens.add(new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "WriteTokenTest", null)); + tokens.add(TextToken.SPACE); + tokens.add(StartBlockToken.START_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + + // } + tokens.add(EndBlockToken.END_BLOCK); + + PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + WriteTokenProcessor writer = new WriteTokenProcessor(); + + Message message = new Message(tokens); + message.setHeader("printer", printer); + message.setHeader("maxLineNumber", 0); + message.setHeader("majorVersion", 0); + message.setHeader("minorVersion", 0); + + writer.process(message); + + String source = printer.toString(); + + System.out.println("- - - - - - - - "); + System.out.print(source); + System.out.println("- - - - - - - - "); + + Assert.assertTrue(source.indexOf("/* Block comment */") != -1); + Assert.assertTrue(source.indexOf("/** Javadoc comment */") != -1); + } +} diff --git a/src/test/java/org/jd/core/v1/loader/ClassPathLoader.java b/src/test/java/org/jd/core/v1/loader/ClassPathLoader.java new file mode 100644 index 00000000..54c5b063 --- /dev/null +++ b/src/test/java/org/jd/core/v1/loader/ClassPathLoader.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.loader; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ClassPathLoader implements Loader { + @Override + public byte[] load(String internalName) throws LoaderException { + InputStream is = this.getClass().getResourceAsStream("/" + internalName + ".class"); + + if (is == null) { + return null; + } else { + try (InputStream in=is; ByteArrayOutputStream out=new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024 * 2]; + int read = in.read(buffer); + + while (read > 0) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + + return out.toByteArray(); + } catch (IOException e) { + throw new LoaderException(e); + } + } + } + + @Override + public boolean canLoad(String internalName) { + return this.getClass().getResource("/" + internalName + ".class") != null; + } +} diff --git a/src/test/java/org/jd/core/v1/loader/NopLoader.java b/src/test/java/org/jd/core/v1/loader/NopLoader.java new file mode 100644 index 00000000..2b149947 --- /dev/null +++ b/src/test/java/org/jd/core/v1/loader/NopLoader.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.loader; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; + +public class NopLoader implements Loader { + @Override + public byte[] load(String internalName) throws LoaderException { + return null; + } + + @Override + public boolean canLoad(String internalName) { + return false; + } +} diff --git a/src/test/java/org/jd/core/v1/loader/ZipLoader.java b/src/test/java/org/jd/core/v1/loader/ZipLoader.java new file mode 100644 index 00000000..f43235fc --- /dev/null +++ b/src/test/java/org/jd/core/v1/loader/ZipLoader.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.loader; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class ZipLoader implements Loader { + protected HashMap map = new HashMap<>(); + + public ZipLoader(InputStream is) throws LoaderException { + byte[] buffer = new byte[1024 * 2]; + + try (ZipInputStream zis = new ZipInputStream(is)) { + ZipEntry ze = zis.getNextEntry(); + + while (ze != null) { + if (ze.isDirectory() == false) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int read = zis.read(buffer); + + while (read > 0) { + out.write(buffer, 0, read); + read = zis.read(buffer); + } + + map.put(ze.getName(), out.toByteArray()); + } + + ze = zis.getNextEntry(); + } + + zis.closeEntry(); + } catch (IOException e) { + throw new LoaderException(e); + } + } + + @Override + public byte[] load(String internalName) throws LoaderException { + return map.get(internalName + ".class"); + } + + @Override + public boolean canLoad(String internalName) { + return map.containsKey(internalName + ".class"); + } +} diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java new file mode 100644 index 00000000..e5b15eb6 --- /dev/null +++ b/src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.printer; + +public class PlainTextMetaPrinter extends PlainTextPrinter { + // --- Printer --- // + public void printStringConstant(String constant, String ownerInternalName) { + sb.append(constant); + sb.append(""); + } + + public void printDeclaration(int flags, String internalTypeName, String name, String descriptor) { + sb.append(name); + sb.append(""); + } + + public void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName) { + sb.append(name); + sb.append(""); + } + + public void startLine(int lineNumber) { + printLineNumber(lineNumber); + + for (int i=0; i"); + while (count-- > 0) { + printLineNumber(0); + sb.append(NEWLINE); + } + sb.append(""); + } + + public void startMarker(int type) { + sb.append(""); + } + + public void endMarker(int type) { + sb.append(""); + } + + protected void printFlags(int flags) { + if ((flags & TYPE_FLAG) != 0) { + sb.append("+TYPE"); + } + if ((flags & FIELD_FLAG) != 0) { + sb.append("+FIELD"); + } + if ((flags & METHOD_FLAG) != 0) { + sb.append("+METHOD"); + } + if ((flags & CONSTRUCTOR_FLAG) != 0) { + sb.append("+CONSTRUCTOR"); + } + } + + protected void printMarker(int marker) { + switch (marker) { + case COMMENT_TYPE: + sb.append("COMMENT"); + break; + case JAVADOC_TYPE: + sb.append("JAVADOC"); + break; + case ERROR_TYPE: + sb.append("ERROR"); + break; + case IMPORT_STATEMENTS_TYPE: + sb.append("IMPORT_STATEMENTS"); + break; + } + } +} diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java new file mode 100644 index 00000000..ee616a94 --- /dev/null +++ b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.printer; + + +import org.jd.core.v1.api.printer.Printer; + +public class PlainTextPrinter implements Printer { + protected static final String TAB = " "; + protected static final String NEWLINE = "\n"; + + protected int indentationCount; + protected StringBuilder sb = new StringBuilder(); + protected int realLineNumber = 0; + protected String format; + + protected boolean escapeUnicodeCharacters; + + public PlainTextPrinter() { + this.escapeUnicodeCharacters = false; + } + + public PlainTextPrinter(boolean escapeUnicodeCharacters) { + this.escapeUnicodeCharacters = escapeUnicodeCharacters; + } + + public String toString() { return sb.toString(); } + + // --- Printer --- // + public void start(int maxLineNumber, int majorVersion, int minorVersion) { + this.indentationCount = 0; + + if (maxLineNumber == 0) { + format = "%4d"; + } else { + int width = 2; + + while (maxLineNumber >= 10) { + width++; + maxLineNumber /= 10; + } + + format = "%" + width + "d"; + } + } + + public void end() {} + + public void printText(String text) { + if (escapeUnicodeCharacters) { + for(int i=0, len=text.length(); i> 24); + + sb.append("\\u"); + sb.append((h <= 9) ? (h + '0') : (h + 'A')); + h = (c >> 16) & 255; + sb.append((h <= 9) ? (h + '0') : (h + 'A')); + h = (c >> 8) & 255; + sb.append((h <= 9) ? (h + '0') : (h + 'A')); + h = (c) & 255; + sb.append((h <= 9) ? (h + '0') : (h + 'A')); + } + } + } else { + sb.append(text); + } + } + + public void printNumericConstant(String constant) { sb.append(constant); } + + public void printStringConstant(String constant, String ownerInternalName) { printText(constant); } + + public void printKeyword(String keyword) { sb.append(keyword); } + + public void printDeclaration(int flags, String internalTypeName, String name, String descriptor) { printText(name); } + + public void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName) { printText(name); } + + public void indent() { + this.indentationCount++; + } + public void unindent() { + if (this.indentationCount > 0) + this.indentationCount--; + } + + public void startLine(int lineNumber) { + printLineNumber(lineNumber); + + for (int i=0; i 0) { + printLineNumber(0); + sb.append(NEWLINE); + } + } + + public void startMarker(int type) {} + + public void endMarker(int type) {} + + protected void printLineNumber(int lineNumber) { + sb.append('['); + sb.append(String.format(format, ++realLineNumber)); + sb.append(':'); + sb.append(String.format(format, lineNumber)); + sb.append("] "); + } +} diff --git a/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java new file mode 100644 index 00000000..d85b998f --- /dev/null +++ b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.services.javasyntax.type.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; + +import java.util.List; + +import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; + +public class PrintTypeVisitor implements TypeVisitor { + protected StringBuilder sb = new StringBuilder(); + + public void reset() { + sb.setLength(0); + } + + public String toString() { + return sb.toString(); + } + + @Override + public void visit(ArrayTypeArguments type) { + printList(type, ", "); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(Types type) { + printList(type, ", "); + } + + @Override + public void visit(DiamondTypeArgument type) {} + + @Override + public void visit(WildcardExtendsTypeArgument type) { + sb.append("? extends "); + type.getType().accept(this); + } + + @Override + public void visit(PrimitiveType type) { + switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(type.getFlags())) { + case FLAG_BOOLEAN: sb.append("boolean"); break; + case FLAG_CHAR: sb.append("char"); break; + case FLAG_FLOAT: sb.append("float"); break; + case FLAG_DOUBLE: sb.append("double"); break; + case FLAG_BYTE: sb.append("byte"); break; + case FLAG_SHORT: sb.append("short"); break; + case FLAG_INT: sb.append("int"); break; + case FLAG_LONG: sb.append("long"); break; + case FLAG_VOID: sb.append("void"); break; + } + + printDimension(type.getDimension()); + } + + @Override + public void visit(ObjectType type) { + sb.append(type.getQualifiedName()); + printTypeArguments(type); + printDimension(type.getDimension()); + } + + public void visit(InnerObjectType type) { + type.getOuterType().accept(this); + sb.append('.').append(type.getName()); + printTypeArguments(type); + printDimension(type.getDimension()); + } + + protected void printTypeArguments(ObjectType type) { + BaseTypeArgument ta = type.getTypeArguments(); + + if (ta != null) { + sb.append('<'); + ta.accept(this); + sb.append('>'); + } + } + + @Override + public void visit(WildcardSuperTypeArgument type) { + sb.append("? super "); + type.getType().accept(this); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(TypeBounds type) { + printList(type, " & "); + } + + @Override + public void visit(TypeParameter type) { + sb.append(type.getIdentifier()); + } + + @Override + public void visit(TypeParameterWithTypeBounds type) { + sb.append(type.getIdentifier()); + sb.append(" extends "); + type.getTypeBounds().accept(this); + } + + @Override + @SuppressWarnings("unchecked") + public void visit(TypeParameters types) { + printList(types, ", "); + } + + @Override public void visit(GenericType type) { + sb.append(type.getIdentifier()); + printDimension(type.getDimension()); + } + + @Override + public void visit(UnknownTypeArgument type) { + sb.append('?'); + } + + protected void printList(List list, String separator) { + int size = list.size(); + + if (size > 0) { + list.get(0).accept(this); + + for (int i=1; i fragments = message.getBody(); + TokenizeJavaFragmentTestVisitor visitor = new TokenizeJavaFragmentTestVisitor(fragments.size() * 3); + + // Create tokens + for (JavaFragment fragment : fragments) { + fragment.accept(visitor); + } + + message.setBody(visitor.getTokens()); + } +} diff --git a/src/test/java/org/jd/core/v1/services/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentTestVisitor.java b/src/test/java/org/jd/core/v1/services/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentTestVisitor.java new file mode 100644 index 00000000..fc7a1bd9 --- /dev/null +++ b/src/test/java/org/jd/core/v1/services/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentTestVisitor.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.services.tokenizer.javafragmenttotoken.visitor; + +import org.jd.core.v1.model.fragment.FlexibleFragment; +import org.jd.core.v1.model.javafragment.*; +import org.jd.core.v1.model.token.TextToken; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.visitor.TokenizeJavaFragmentVisitor; + +public class TokenizeJavaFragmentTestVisitor extends TokenizeJavaFragmentVisitor { + protected static final TextToken SUFFIX = new TextToken("-->"); + + protected int size; + protected StringBuilder sb = new StringBuilder(200); + + public TokenizeJavaFragmentTestVisitor(int initialCapacity) { + super(initialCapacity); + } + + @Override + public void visit(EndBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(EndBodyInParameterFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(SpaceSpacerFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(EndBodyFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(EndSingleStatementBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(EndStatementsBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(ImportsFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(SpacerBetweenMembersFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(SpacerFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartBodyFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartSingleStatementBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartStatementsBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartStatementsDoWhileBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartStatementsInfiniteForBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartStatementsInfiniteWhileBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + @Override + public void visit(StartStatementsTryBlockFragment fragment) { + addPrefix(fragment); + super.visit(fragment); + addSuffix(); + } + + protected void addPrefix(FlexibleFragment fragment) { + sb.setLength(0); + sb.append("<-- "); + sb.append(fragment.getMinimalLineCount()); + sb.append(','); + sb.append(fragment.getInitialLineCount()); + sb.append(','); + sb.append(fragment.getMaximalLineCount()); + sb.append(':'); + sb.append(fragment.getWeight()); + + if (fragment.getLabel() != null) { + sb.append(" '"); + sb.append(fragment.getLabel()); + sb.append('\''); + } + + sb.append(' '); + tokens.add(new TextToken(sb.toString())); + size = tokens.size(); + } + + protected void addSuffix() { + if (size < tokens.size()) { + tokens.add(TextToken.SPACE); + } + tokens.add(SUFFIX); + } +} diff --git a/src/test/java/org/jd/core/v1/util/ControlFlowGraphPlantUMLWriter.java b/src/test/java/org/jd/core/v1/util/ControlFlowGraphPlantUMLWriter.java new file mode 100644 index 00000000..b7eac98f --- /dev/null +++ b/src/test/java/org/jd/core/v1/util/ControlFlowGraphPlantUMLWriter.java @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.util; + +import org.jd.core.v1.model.classfile.Method; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ByteCodeWriter; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.zip.Deflater; + +import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; + +/** + * A state diagram writer. + * + * http://plantuml.com/state.html + * http://plantuml.com/plantuml + */ +public class ControlFlowGraphPlantUMLWriter { + //protected static final String PLANTUML_URL_PREFIX = "http://plantuml.com/plantuml/png/"; + protected static final String PLANTUML_URL_PREFIX = "http://plantuml.com/plantuml/svg/"; + protected static final char[] PLANTUML_ENCODE_6_BIT = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".toCharArray(); + protected static final BasicBlockComparator BASIC_BLOCK_COMPARATOR = new BasicBlockComparator(); + + public static String write(ControlFlowGraph cfg) { + if (cfg.getBasicBlocks() == null) { + return null; + } else { + boolean dark = true; + HashSet set = new HashSet<>(); + + search(set, cfg.getStart()); + + DefaultList list = new DefaultList<>(set); + list.sort(BASIC_BLOCK_COMPARATOR); + + StringBuilder sb = new StringBuilder(); + + //sb.append("scale 0.6\n"); + //sb.append("scale max 2000 width\n"); + //sb.append("skinparam shadowing false\n"); + sb.append("skinparam state {\n"); + sb.append(" BackgroundColor<> #BBD7B7\n"); + sb.append(" BorderColor<> Green\n"); + sb.append(" BackgroundColor<> PowderBlue\n"); + sb.append(" BorderColor<> DodgerBlue\n"); + sb.append(" BackgroundColor<> Orange\n"); + sb.append(" BorderColor<> #FF740E\n"); + sb.append("}\n"); + + if (dark) { + sb.append("skinparam BackgroundColor #2B2B2B\n"); + sb.append("skinparam state {\n"); + sb.append(" StartColor #999999\n"); + sb.append(" BackgroundColor #D6BF55\n"); + sb.append(" BorderColor #F6DF57\n"); + sb.append("}\n"); + sb.append("skinparam sequence {\n"); + sb.append(" ArrowColor #999999\n"); + sb.append(" ArrowFontColor #AAAAAA\n"); + sb.append("}\n"); + } else { + //sb.append("skinparam BackgroundColor #DDDDDD\n"); + sb.append("skinparam state {\n"); + sb.append(" BorderColor Gold\n"); + sb.append("}\n"); + sb.append("skinparam sequence {\n"); + sb.append(" ArrowColor Black\n"); + sb.append("}\n"); + } + + Method method = cfg.getMethod(); + + for (BasicBlock basicBlock : list) + writeState(sb, method, basicBlock); + + for (BasicBlock basicBlock : list) + writeLink(sb, basicBlock); + + return sb.toString(); + } + } + + protected static void search(HashSet set, BasicBlock basicBlock) { + if (set.contains(basicBlock) == false) { + set.add(basicBlock); + + switch (basicBlock.getType()) { + case TYPE_START: + case TYPE_STATEMENTS: + case TYPE_LOOP: + case TYPE_GOTO: + case TYPE_GOTO_IN_TERNARY_OPERATOR: + search(set, basicBlock.getNext()); + break; + case TYPE_CONDITIONAL_BRANCH: + case TYPE_JSR: + search(set, basicBlock.getNext()); + search(set, basicBlock.getBranch()); + break; + case TYPE_SWITCH: + search(set, basicBlock.getNext()); + case TYPE_SWITCH_DECLARATION: + for (SwitchCase switchCase : basicBlock.getSwitchCases()) + search(set, switchCase.getBasicBlock()); + break; + case TYPE_TRY: + case TYPE_TRY_JSR: + case TYPE_TRY_ECLIPSE: + search(set, basicBlock.getSub1()); + case TYPE_TRY_DECLARATION: + search(set, basicBlock.getNext()); + for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) + search(set, exceptionHandler.getBasicBlock()); + break; + case TYPE_IF: + search(set, basicBlock.getCondition()); + search(set, basicBlock.getNext()); + search(set, basicBlock.getSub1()); + break; + case TYPE_IF_ELSE: + case TYPE_TERNARY_OPERATOR: + search(set, basicBlock.getNext()); + case TYPE_CONDITION_TERNARY_OPERATOR: + search(set, basicBlock.getCondition()); + case TYPE_CONDITION_OR: + case TYPE_CONDITION_AND: + search(set, basicBlock.getSub1()); + search(set, basicBlock.getSub2()); + break; + } + } + } + + protected static void writeState(StringBuilder sb, Method method, BasicBlock basicBlock) { + String id = getStateId(basicBlock); + + switch (basicBlock.getType()) { + case TYPE_STATEMENTS: + case TYPE_IF: + case TYPE_IF_ELSE: + case TYPE_TERNARY_OPERATOR: + case TYPE_TRY: + case TYPE_TRY_JSR: + case TYPE_TRY_ECLIPSE: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append("<>\n"); + writeStateOffsets(sb, id, basicBlock); + writeLineNumbers(sb, id, basicBlock); + writeStateEnd(sb, id, basicBlock.getNext(), "next"); + writeStatePredecessors(sb, id, basicBlock); + writeStateCode(sb, id, method, basicBlock); + break; + case TYPE_RETURN: + if (basicBlock == RETURN) { + break; + } + case TYPE_THROW: + case TYPE_RETURN_VALUE: + case TYPE_RET: + case TYPE_SWITCH: + case TYPE_INFINITE_GOTO: + case TYPE_GOTO_IN_TERNARY_OPERATOR: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append("<>\n"); + writeStateOffsets(sb, id, basicBlock); + writeLineNumbers(sb, id, basicBlock); + writeStatePredecessors(sb, id, basicBlock); + writeStateCode(sb, id, method, basicBlock); + break; + case TYPE_CONDITION: + case TYPE_CONDITION_OR: + case TYPE_CONDITION_AND: + case TYPE_CONDITION_TERNARY_OPERATOR: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append("<>\n"); + writeStateOffsets(sb, id, basicBlock); + writeLineNumbers(sb, id, basicBlock); + writeInverseCondition(sb, id, basicBlock); + writeStateCode(sb, id, method, basicBlock); + break; + case TYPE_JSR: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append('\n'); + writeStateOffsets(sb, id, basicBlock); + writeLineNumbers(sb, id, basicBlock); + writeStateEnd(sb, id, basicBlock.getNext(), "next"); + writeStateEnd(sb, id, basicBlock.getBranch(), "branch"); + writeStatePredecessors(sb, id, basicBlock); + writeStateCode(sb, id, method, basicBlock); + break; + case TYPE_CONDITIONAL_BRANCH: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append('\n'); + writeStateOffsets(sb, id, basicBlock); + writeLineNumbers(sb, id, basicBlock); + writeStatePredecessors(sb, id, basicBlock); + writeStateCode(sb, id, method, basicBlock); + break; + case TYPE_TRY_DECLARATION: + case TYPE_GOTO: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append("<>\n"); + writeStateOffsets(sb, id, basicBlock); + writeLineNumbers(sb, id, basicBlock); + writeStatePredecessors(sb, id, basicBlock); + writeStateCode(sb, id, method, basicBlock); + break; + case TYPE_SWITCH_DECLARATION: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append("<>\n"); + writeStateOffsets(sb, id, basicBlock); + writeLineNumbers(sb, id, basicBlock); + writeStatePredecessors(sb, id, basicBlock); + writeStateCode(sb, id, method, basicBlock); + break; + case TYPE_LOOP: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append(" {\n"); + sb.append("[*] --> ").append(getStateId(basicBlock.getSub1())).append('\n'); + + HashSet set = new HashSet<>(); + + search(set, basicBlock.getSub1()); + + set.remove(basicBlock); + + for (BasicBlock bb : set) + writeState(sb, method, bb); + + for (BasicBlock bb : set) + writeLink(sb, bb); + + sb.append("}\n"); + writeStateOffsets(sb, id, basicBlock); + writeStateEnd(sb, id, basicBlock.getNext(), "next"); + writeStatePredecessors(sb, id, basicBlock); + break; + case TYPE_JUMP: + sb.append("state \"").append(basicBlock.getTypeName()).append(" : ").append(basicBlock.getIndex()).append("\" as ").append(id).append("<>\n"); + sb.append(id).append(" : offset = ").append(basicBlock.getFromOffset()).append("\n"); + sb.append(id).append(" : targetOffset = ").append(basicBlock.getToOffset()).append("\n"); + break; + } + } + + protected static void writeStateOffsets(StringBuilder sb, String id, BasicBlock basicBlock) { + sb.append(id).append(" : fromOffset = ").append(basicBlock.getFromOffset()).append("\n"); + sb.append(id).append(" : toOffset = ").append(basicBlock.getToOffset()).append("\n"); + } + + protected static void writeStatePredecessors(StringBuilder sb, String id, BasicBlock basicBlock) { + Set predecessors = basicBlock.getPredecessors(); + + if (!predecessors.isEmpty()) { + sb.append(id).append(" : predecessors = ["); + + Iterator iterator = predecessors.iterator(); + + sb.append(iterator.next().getIndex()); + while (iterator.hasNext()) { + sb.append(", ").append(iterator.next().getIndex()); + } + + sb.append("]\n"); + } + } + + protected static void writeInverseCondition(StringBuilder sb, String id, BasicBlock basicBlock) { + if (basicBlock.matchType(TYPE_CONDITION|TYPE_CONDITION_TERNARY_OPERATOR|TYPE_GOTO_IN_TERNARY_OPERATOR)) { + sb.append(id).append(" : inverseCondition = ").append(basicBlock.mustInverseCondition()).append("\n"); + } + } + + protected static void writeStateCode(StringBuilder sb, String id, Method method, BasicBlock basicBlock) { + if ((method != null) && basicBlock.matchType(GROUP_CODE) && (basicBlock.getFromOffset() < basicBlock.getToOffset())) { + String byteCode = ByteCodeWriter.write(" ", method, basicBlock.getFromOffset(), basicBlock.getToOffset()); + + byteCode = byteCode.substring(0, byteCode.length()-1).replaceAll("\n", "\\\\n\\\\\n"); + sb.append(id).append(" : code =\\n\\\n").append(byteCode).append("\n"); + } + } + + protected static void writeLineNumbers(StringBuilder sb, String id, BasicBlock basicBlock) { + if (basicBlock.getFirstLineNumber() > 0) { + sb.append(id).append(" : firstLineNumber = ").append(basicBlock.getFirstLineNumber()).append("\n"); + } + if (basicBlock.getLastLineNumber() > 0) { + sb.append(id).append(" : lastLineNumber = ").append(basicBlock.getLastLineNumber()).append("\n"); + } + } + + protected static void writeStateEnd(StringBuilder sb, String id, BasicBlock basicBlock, String label) { + if (basicBlock == END) { + sb.append(id).append(" : ").append(label).append(" = ◉\n"); + } + } + + protected static void writeLink(StringBuilder sb, BasicBlock basicBlock) { + String id = getStateId(basicBlock); + + switch (basicBlock.getType()) { + case TYPE_START: + sb.append("[*] --> ").append(getStateId(basicBlock.getNext())).append('\n'); + break; + case TYPE_STATEMENTS: + case TYPE_GOTO: + case TYPE_GOTO_IN_TERNARY_OPERATOR: + writeLink(sb, id, basicBlock.getNext(), "next"); + break; + case TYPE_CONDITIONAL_BRANCH: + writeLink(sb, id, basicBlock.getNext(), "next"); + writeLink(sb, id, basicBlock.getBranch(), "branch"); + break; + case TYPE_SWITCH: + writeLink(sb, id, basicBlock.getNext(), "next"); + case TYPE_SWITCH_DECLARATION: + BasicBlock next = basicBlock.getNext(); + + for (SwitchCase switchCase : basicBlock.getSwitchCases()) { + if ((switchCase.getBasicBlock() != END) && (switchCase.getBasicBlock() != next)) { + writeLink(sb, id, switchCase.getBasicBlock(), switchCase.isDefaultCase() ? "default" : "case: " + switchCase.getValue()); + } + } + break; + case TYPE_TRY: + case TYPE_TRY_JSR: + case TYPE_TRY_ECLIPSE: + writeLink(sb, id, basicBlock.getSub1(), "try"); + writeLink(sb, id, basicBlock.getNext(), "next"); + + for (ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { + sb.append(id).append(" --> ").append(getStateId(exceptionHandler.getBasicBlock())); + + if (exceptionHandler.getInternalThrowableName() == null) { + sb.append(" : finally"); + } else { + sb.append(" : catch ").append(exceptionHandler.getInternalThrowableName()); + + if (exceptionHandler.getOtherInternalThrowableNames() != null) { + for (String name : exceptionHandler.getOtherInternalThrowableNames()) { + sb.append("\\ncatch ").append(name); + } + } + } + + sb.append('\n'); + } + break; + case TYPE_TRY_DECLARATION: + writeLink(sb, id, basicBlock.getNext(), "try"); + + for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { + sb.append(id).append(" --> ").append(getStateId(exceptionHandler.getBasicBlock())); + + if (exceptionHandler.getInternalThrowableName() == null) { + sb.append(" : finally"); + } else { + sb.append(" : catch ").append(exceptionHandler.getInternalThrowableName()); + + if (exceptionHandler.getOtherInternalThrowableNames() != null) { + for (String name : exceptionHandler.getOtherInternalThrowableNames()) { + sb.append("\\ncatch ").append(name); + } + } + } + + sb.append('\n'); + } + break; + case TYPE_JSR: + writeLink(sb, id, basicBlock.getNext(), "next"); + writeLink(sb, id, basicBlock.getBranch(), "jsr"); + break; + case TYPE_LOOP: + if (basicBlock.getNext() != null) { + writeLink(sb, id, basicBlock.getNext(), "next"); + } + break; + case TYPE_IF_ELSE: + case TYPE_TERNARY_OPERATOR: + writeLink(sb, id, basicBlock.getSub2(), "else"); + case TYPE_IF: + writeLink(sb, id, basicBlock.getCondition(), "condition"); + writeLink(sb, id, basicBlock.getNext(), "next"); + writeLink(sb, id, basicBlock.getSub1(), "then"); + break; + case TYPE_CONDITION_TERNARY_OPERATOR: + writeLink(sb, id, basicBlock.getCondition(), "condition"); + case TYPE_CONDITION_OR: + case TYPE_CONDITION_AND: + writeLink(sb, id, basicBlock.getSub1(), "left"); + writeLink(sb, id, basicBlock.getSub2(), "right"); + break; + } + } + + protected static void writeLink(StringBuilder sb, String fromId, BasicBlock to, String label) { + if (to == SWITCH_BREAK) { + sb.append("state \"SWITCH_BREAK\" as switch_break_").append(fromId).append('\n'); + sb.append(fromId).append(" --> switch_break_").append(fromId).append(" : ").append(label).append('\n'); + } else if (to == LOOP_START) { + sb.append("state \"LOOP_START\" as start_loop_").append(fromId).append('\n'); + sb.append(fromId).append(" --> start_loop_").append(fromId).append(" : ").append(label).append('\n'); + } else if (to == LOOP_CONTINUE) { + sb.append("state \"LOOP_CONTINUE\" as continue_loop_").append(fromId).append('\n'); + sb.append(fromId).append(" --> continue_loop_").append(fromId).append(" : ").append(label).append('\n'); + } else if (to == LOOP_END) { + sb.append("state \"LOOP_END\" as end_loop_").append(fromId).append('\n'); + sb.append(fromId).append(" --> end_loop_").append(fromId).append(" : ").append(label).append('\n'); + } else if (to == RETURN) { + sb.append("state \"RETURN\" as return_").append(fromId).append('\n'); + sb.append(fromId).append(" --> return_").append(fromId).append(" : ").append(label).append('\n'); + } else if (to != END) { + sb.append(fromId).append(" --> state_").append(to.getIndex()).append(" : ").append(label).append('\n'); + } + } + + protected static String getStateId(BasicBlock basicBlock) { + return (basicBlock == END) || (basicBlock == LOOP_END) ? "[*]" : "state_" + basicBlock.getIndex(); + } + + public static String writePlantUMLUrl(String plantuml) throws Exception { + byte[] input = plantuml.getBytes("UTF-8"); + + // Compress + Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, true); + + deflater.setInput(input); + deflater.finish(); + + byte[] output = new byte[input.length * 2]; + int compressedDataLength = deflater.deflate(output); + + if (deflater.finished()) { + // Encode + final StringBuilder sb = new StringBuilder((output.length*4 + 2) / 3); + + for (int i=0; i> 2; + int c2 = ((b1 & 0x3) << 4) | (b2 >> 4); + int c3 = ((b2 & 0xF) << 2) | (b3 >> 6); + int c4 = b3 & 0x3F; + + sb.append(PLANTUML_ENCODE_6_BIT[c1 & 0x3F]); + sb.append(PLANTUML_ENCODE_6_BIT[c2 & 0x3F]); + sb.append(PLANTUML_ENCODE_6_BIT[c3 & 0x3F]); + sb.append(PLANTUML_ENCODE_6_BIT[c4 & 0x3F]); + } + + public static class BasicBlockComparator implements Comparator { + @Override + public int compare(BasicBlock bb1, BasicBlock bb2) { + return bb1.getIndex() - bb2.getIndex(); + } + + @Override + public boolean equals(Object other) { + return this==other; + } + } +} diff --git a/src/test/java/org/jd/core/v1/util/PatternMaker.java b/src/test/java/org/jd/core/v1/util/PatternMaker.java new file mode 100644 index 00000000..d1463a7a --- /dev/null +++ b/src/test/java/org/jd/core/v1/util/PatternMaker.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.util; + +public class PatternMaker { + public static String make (String first, String... next) { + StringBuilder sb = new StringBuilder("(?s).*"); + + sb.append(replace(first)); + + for (String s : next) { + sb.append("[^\\n\\r]*").append(replace(s)); + } + + sb.append(".*"); + + return sb.toString(); + } + + public static String make(String s) { + return "(?s).*" + replace(s) + ".*"; + } + + protected static String replace(String s) { + return s + .replace("[", "\\[") + .replace("]", "\\]") + .replace("(", "\\(") + .replace(")", "\\)") + .replace(".", "\\.") + .replace("?", "\\?") + .replace("+", "\\+") + .replace("*", "\\*") + .replace("|", "\\|") + .replace("^", "\\^") + .replaceAll("\\s*\\{\\s*", "[^\\\\n\\\\r]*\\\\{[^\\\\n\\\\r]*") + .replaceAll("\\s*\\}\\s*", "[^\\\\n\\\\r]*\\\\}[^\\\\n\\\\r]*") + .replace(",", "[^\\n\\r]*,"); + } +} diff --git a/src/test/resources/apk/ContactManager.apk b/src/test/resources/apk/ContactManager.apk new file mode 100644 index 0000000000000000000000000000000000000000..418f504bde28ee5fae806e2e060f488e7abe791f GIT binary patch literal 25931 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 Q@CA_y;SJ_Rp)sWX1&8eh#{d8T literal 0 HcmV?d00001 diff --git a/src/test/resources/java/org/jd/core/test/AdvancedSwitch.java b/src/test/resources/java/org/jd/core/test/AdvancedSwitch.java new file mode 100644 index 00000000..699b3993 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/AdvancedSwitch.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class AdvancedSwitch { + + enum TestEnum { + A, B, C; + } + + public void switchEnum(TestEnum te) { + System.out.println("start"); + + switch (te) { + case A: + System.out.println("A"); + case B: + System.out.println("B"); + break; + case C: + System.out.println("C"); + break; + default: + System.out.println("default"); + } + + System.out.println("end"); + } + + public void switchString(String str) { + System.out.println("start"); + + switch (str) { + case "One": + System.out.println(1); + break; + case "POe": + System.out.println("same hashcode than 'One'"); + break; + case "Two": + System.out.println(2); + break; + default: + System.out.println("?"); + break; + } + + System.out.println("end"); + } +} diff --git a/src/test/resources/java/org/jd/core/test/AnnotatedClass.java b/src/test/resources/java/org/jd/core/test/AnnotatedClass.java new file mode 100644 index 00000000..aad64e12 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/AnnotatedClass.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import org.jd.core.test.annotation.Author; +import org.jd.core.test.annotation.Name; +import org.jd.core.test.annotation.Quality; +import org.jd.core.test.annotation.Value; + +import java.io.Serializable; +import java.io.Writer; +import java.net.UnknownHostException; +import java.util.ArrayList; + +@Quality(Quality.Level.HIGH) +@Author(value=@Name(salutation="Mr", value="Donald", last="Duck"), contributors={@Name("Huey"), @Name("Dewey"), @Name("Louie")}) +public class AnnotatedClass extends ArrayList implements Serializable, Cloneable { + @Value(z = true) + protected boolean z1; + + @Value(b = -15) + protected byte b1; + + @Value(s = -15) + protected short s1; + + @Value(i = 1) + protected int i1 = 1; + + @Value(l = 1234567890123456789L) + protected long l1; + + @Value(f = 123.456F) + protected float f1; + + @Value(d = 789.101112D) + protected double d1; + + @Value(str = "str") + protected String str1; + + @Value(str = "str \u0083 \u0909 \u1109") // "str � ? ?" + protected String str2; + + @Value(clazz = String.class) + protected Class clazz; + + public int add(int i1, int i2) { + return i1 + i2; + } + + public void ping(@Deprecated Writer writer, @Deprecated @Value(str="localhost") @SuppressWarnings("all") String host, long timeout) throws UnknownHostException, UnsatisfiedLinkError { + // ... + } + + public static class SimpleInnerClass { + protected int i; + } +} diff --git a/src/test/resources/java/org/jd/core/test/AnonymousClass.java b/src/test/resources/java/org/jd/core/test/AnonymousClass.java new file mode 100644 index 00000000..0466b7ea --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/AnonymousClass.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import org.jd.core.test.annotation.Name; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; + +public class AnonymousClass { + + protected long time = System.currentTimeMillis(); + + public void test(Enumeration e, String s) { + System.out.println("start"); + + Object obj = new Object() { + public String toString() { + return "toString() return " + super.toString() + " at " + time; + } + }; + + System.out.println(obj); + + System.out.println("end"); + } + + LinkedList list; + + public void anonymousImplInterface(final String s1, @Name("s2") final String s2, String s3, final int i1) { + System.out.println("start"); + + final long l1 = System.currentTimeMillis(); + + Enumeration e = new Enumeration() { + Iterator i = list.iterator(); + + public boolean hasMoreElements() { + time = System.currentTimeMillis(); + return i.hasNext() && (s1 == s2) && (i1 > l1); + } + + public Object nextElement() { + return i.next(); + } + }; + + test(e, + "test"); + + System.out.println("end"); + } + + public void anonymousImplClass(final String s1, final String s2, String s3) { + System.out.println("start"); + + final int i = s1.length(); + + System.out.println("2" + (new StringWrapper(123456L) { + + public String toString(String a, String b) { + time = System.currentTimeMillis(); + if ((s1 == s2) && (i == 5)) + return s1; + else + return s2; + } + + }) + "3"); + + System.out.println("end"); + } + + public void twoAnonymousClasses() { + System.out.println("start"); + + final Object abc = "abc"; + final Object def = "def"; + + Serializable serializable = new Serializable() { + public boolean equals(Object obj) { + + final Object ghi = "ghi"; + final Object jkl = "jkl"; + + Serializable serializable = new Serializable() { + public boolean equals(Object obj) { + + Object ghi = "overwrite ghi"; + Object jkl = "overwrite jkl"; + + return abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj); + } + }; + + return abc.equals(obj) || def.equals(obj); + } + }; + + System.out.println("end"); + } + + public static class StringWrapper { + protected long l; + + public StringWrapper(long l) { + this.l = l & 128L; + } + } +} diff --git a/src/test/resources/java/org/jd/core/test/Array.java b/src/test/resources/java/org/jd/core/test/Array.java new file mode 100644 index 00000000..7b7e8562 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Array.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.io.Serializable; + +public class Array implements Serializable { + + public void declarations() { + int[] i1 = new int[1]; + int[][] i2 = new int[1][]; + int[][][] i3 = new int[1][][]; + int[][][] i4 = new int[1][2][]; + int[][][][] i5 = new int[1][2][][]; + + String[] s1 = new String[1]; + String[][] s2 = new String[1][]; + String[][][] s3 = new String[1][][]; + String[][][] s4 = new String[1][2][]; + String[][][][] s5 = new String[1][2][][]; + } + + public void init() { + byte[] b1 = { 1, 2 }; + byte[][] b2 = { { 1, 2 } }; + byte[][][][] b3 = { { { { 3, 4 } } } }; + + int[][] ia = new int[][] { { + + 0, 1, + + 2}, { + 4} }; + + int[] ia1 = new int[] { + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122 }; + + int size = ia.length; + + System.out.println(ia[1][0]); + + int[][] ia2 = new int[3][]; + + testException1(new Exception[] { new Exception("1") }); + + testException1(new Exception[] { }); + + testException2(new Exception[][] { + { new Exception("1") }, + { new Exception("2"), new Exception("3") } + }); + + testException3(new Exception[][][] { + { { new Exception("1") } }, + { { new Exception("2"), new Exception("3") } }, + new Exception[0][] + }); + + testException3(new Exception[][][] { + { }, + { { new Exception("1") } }, + { { new Exception("2"), new Exception("3") } }, + { { } }, + { } + }); + + testInt1(new int[] { 1 }); + + testInt2(new int[][] { { 1 }, { 2 } }); + + testInt3(new int[][][] { + { // 0 + { // 0,0 + 0, // 0,0,0 + 1 // 0,0,1 + } + }, + { // 1 + { // 1,0 + 100 // 1,0,0 + } + } + }); + } + + private void testException1(Exception[] es) {} + + private void testException2(Exception[][] es) {} + + private void testException3(Exception[][][] es) {} + + private void testInt1(int[] es) {} + + private void testInt2(int[][] es) {} + + private void testInt3(int[][][] es) {} +} diff --git a/src/test/resources/java/org/jd/core/test/Assert.java b/src/test/resources/java/org/jd/core/test/Assert.java new file mode 100644 index 00000000..26bff6d2 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Assert.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class Assert implements Serializable { + + public static void test1(int i) + { + System.out.println("a"); + assert true : "true"; + assert false : "false"; + assert (i == 0) || (i == 1); + assert (i == 2) && (i < 3); + System.out.println("b"); + } + + public static void test2(int i) + { + System.out.println("a"); + assert i == 0 : + "boom"; + System.out.println("b"); + } + + + public static void test3(int i) + { + System.out.println("a"); + assert new BigDecimal(i) == BigDecimal.ONE; + System.out.println("b"); + } + + public static void test4() + { + System.out.println("a"); + assert check() : "boom"; + System.out.println("b"); + } + + protected static boolean check() + { + return true; + } + + void testBug341(int i) { + assert i > 0; + } +} diff --git a/src/test/resources/java/org/jd/core/test/Basic.java b/src/test/resources/java/org/jd/core/test/Basic.java new file mode 100644 index 00000000..598c17ff --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Basic.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.io.Serializable; + +public class Basic implements Serializable { + protected static final long serialVersionUID = 9506606333927794L; + + protected static long long12 = 12L; + protected static long long34 = 34L; + + protected short short56 = 56; + protected int int78 = 78; + protected int index = + getClass() + .getName() + .indexOf('B'); + + public void printHelloWorld() { + System.out.println("hello"); + System.out.println("world"); + } + + public void declarations(int i) { + String str1 = "3 == " + (i+1) + " ?"; + String str2 = str1.valueOf("abc \b \f \n \r \t \" \007 def"); + + char c1 = 'a'; + char c2 = '€'; + char c3 = '\''; + char c4 = c3 = c2 = c1 = Character.toUpperCase('x'); + + Class class1; + Class class2; + Class class3; + + class1 = class2 = class3 = String.class; + + Class class4; + Class class5; + Class class6; + String[] args1; + String[] args2; + + class4 = class5 = doSomething(class6 = String.class, args1 = args2 = new String[] { "do", "something" }); + + int j = 1, k[] = { 1 }, l[][] = {{ 1 }, { 2 }, {}}; + String stringNull = null; + } + + public String[] createStringArray(String s) { + return new String[] { s, s + '?' }; + } + + protected static Class doSomething(Class clazz, String[] args) { + return clazz; + } + + public void instanceOf() { + System.out.println("start"); + + if (this instanceof Object) { + System.out.println("nice !"); + } + + System.out.println("end"); + } + + public void operator(int i) { + System.out.println("start"); + + int k = 50 / (25 + (i = 789)); + + k = i += 100; + + int78 = i = int78 += 456; + int78 = 50 / (25 + (int78 = 789)); + + i = ++int78; + i = int78++; + i *= 10; + + int78 = ++i; + int78 = i++; + int78 *= 10; + + long34 = ++long12; + long34 = long12++; + long34 *= 10; + + i = (int)long12 + int78; + + i = k ^ 0xFF; + i |= 0x07; + + System.out.println("end"); + } + + public int scope(int i) { + int result; + + System.out.println("start"); + + if (i > 10) { + if (i % 2 == 0) { + result = 1; + } else { + int k = i; + result = k + 2; + } + } else { + result = short56; + } + + if (i % 2 == 0) { + return result; + } + + long long12 = 123L; + int int78 = getInt78(new Object[] { this }, (short)5); + + i = (int)(Basic.long12 + long12) + (this.int78 + int78); + + System.out.println("end"); + + return 0; + } + + public String readLine() { + StringBuffer result = new StringBuffer(); + for (;;) { + int intRead = read(); + if (intRead == -1) { + return result.length() == 0 ? null : result.toString(); + } + char c = (char)intRead; + if (c == '\n') break; + result.append(c); + } + return result.toString(); + } + + public static native int read(); + + protected static double pi = Math.PI; + protected static double e = Math.E; + protected static int int_max = Integer.MAX_VALUE; + protected static long long_min = Long.MIN_VALUE; + + public long returnLong() { + return System.currentTimeMillis(); + } + + public double returnDouble() { + return Double.MAX_VALUE; + } + + private String doSomethingWithString(String str) { + if (str == null) { + str = "null"; + } else { + if (str.length() == 0) { + return "empty"; + } + return str + str; + } + + return str; + } + + public Basic getLast(Object[] objects) { + return (objects == null) || (objects.length == 0) ? null : + (Basic)objects[objects.length-1]; + } + + public int getInt78(Object[] objects, short index) { + return ((Basic)objects[index]).int78; + } +} \ No newline at end of file diff --git a/src/test/resources/java/org/jd/core/test/BreakContinue.java b/src/test/resources/java/org/jd/core/test/BreakContinue.java new file mode 100644 index 00000000..9c951a79 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/BreakContinue.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class BreakContinue { + + public void doWhileContinue(int i) { + System.out.println("start"); + + do { + System.out.println("a"); + + if (i == 1) { + continue; + } + if (i == 2) { + continue; + } + + System.out.println("b"); + } while (i > 5 && i < 10); + + System.out.println("end"); + } + + public void tripleWhile1(int i) { + System.out.println("start"); + + label: while (i > 1) { + while (i > 2) { + while (i > 3) { + System.out.println("a"); + + if (i == 4) { + continue label; + } + if (i == 5) { + break label; + } + + System.out.println("b"); + } + } + } + + System.out.println("end"); + } + + public void tripleWhile2(int i) { + System.out.println("start"); + + while (i > 1) { + label: while (i > 2) { + while (i > 3) { + System.out.println("a"); + + if (i == 4) { + continue label; + } + if (i == 5) { + break label; + } + + System.out.println("b"); + } + } + } + + System.out.println("end"); + } + + public void tripleDoWhile1(int i) { + System.out.println("start"); + + label: do { + do { + do { + System.out.println("a"); + + if (i == 1) { + continue label; + } + if (i == 2) { + break label; + } + + System.out.println("b"); + } while (i > 3); + } while (i > 4); + } while (i > 5); + + System.out.println("end"); + } + + public void tripleDoWhile2(int i) { + System.out.println("start"); + + label0: do { + label: do { + do { + System.out.println("a"); + + if (i == 1) { + continue label; + } + if (i == 2) { + break label; + } + + System.out.println("b"); + } while (i > 3); + } while (i > 4); + } while (i > 5); + + System.out.println("end"); + } + + public int doWhileWhileIf(int i0, int i1) { + System.out.println("start"); + + label_0: do { + System.out.println("a"); + + label_1: for (int i=i0; i 0); + + System.out.println("end"); + + return i0; + } + + public int doWhileWhileTryBreak(int i0, int i1) { + System.out.println("start"); + + label_0: do { + while (i0 < 10) { + try { + if (i0 / i1 != 2) { + i0 = i0 + 1; + } else { + break label_0; + } + } catch (ArithmeticException e) { + System.out.println("div by 0"); + } + } + + i1 = i1 + -1; + } while (i1 > 0); + + System.out.println("end"); + + return i0; + } +} diff --git a/src/test/resources/java/org/jd/core/test/Constructors.java b/src/test/resources/java/org/jd/core/test/Constructors.java new file mode 100644 index 00000000..b58f6572 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Constructors.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class Constructors { + + public static class SuperType { + protected short short56; + protected int int78; + + public SuperType() { + this.short56 = 1; + this.int78 = 78; + } + + public SuperType(short short56) { + this.short56 = short56; + this.int78 = 78; + } + } + + public static class Type extends SuperType { + protected short short123; + + public Type() { + this.short123 = 1; + } + + public Type(short short56) { + super(short56); + this.short123 = 2; + } + + public Type(short short56, int int78) { + this(short56); + this.int78 = int78; + this.short123 = 3; + } + } +} diff --git a/src/test/resources/java/org/jd/core/test/DoWhile.java b/src/test/resources/java/org/jd/core/test/DoWhile.java new file mode 100644 index 00000000..d09c53ea --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/DoWhile.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class DoWhile { + + public void doWhileTry(int i, Object o) { + do { + System.out.println("a"); + try + { + System.out.println("b"); + } + catch (RuntimeException e) + { + System.out.println("c"); + } + } + while (i<10); + } + + public void doWhile() { + System.out.println("start"); + + do + System.out.println("'this' is null!!"); + while (this == null); + + System.out.println("end"); + } + + public void doWhile2() { + System.out.println("a"); + int i = 0; + + do + { + System.out.println("b"); + i++; + } + while (i < 10); + + System.out.println("c"); + } + + public void doWhileIf() { + int i=0; + + System.out.println("a"); + + do + { + System.out.println("b"); + if (i == 4) + System.out.println("c"); + System.out.println("d"); + i++; + } + while (i<10); + + System.out.println("e"); + } + + public int doWhileWhile(int i0, int i1) { + do + { + while (i0 < 10) + { + i0 = i0 + 1; + } + + i1 = i1 + -1; + } + while (i1 > 0); + + return i0; + } + + private static void emptyDoWhile() { + int i = 10; + + do; + while (i < 10); + } + + private static void doWhileTestPreInc() { + float i = 10; + + do + { + System.out.println("2"); + } + while (--i > 0); + } + + private static void doWhileTestPostInc() { + float i = 10; + + do + { + System.out.println("2"); + } + while (i-- > 0); + } + + public void doWhileORAndANDConditions(int i) + { + System.out.println("start"); + + do { + System.out.println("a"); + } while ((i==1 || (i==5 && i==6 && i==7) || i==8 || (i==9 && i==10 && i==11)) && (i==4 || (i%200) > 50) && (i>3 || i>4)); + + System.out.println("end"); + } + + public void doWhileAndANDConditions(int i) + { + System.out.println("start"); + + do { + System.out.println("a"); + } while ((i==1 && (i==5 || i==6 || i==7) && i==8 && (i==9 || i==10 || i==11)) || (i==4 && (i%200) > 50) || (i>3 && i>4)); + + System.out.println("end"); + } + + public static void doWhileTryFinally(int i) { + System.out.println("start"); + + do { + try { + System.out.println("a"); + } finally { + i++; + } + } while (i < 5); + + System.out.println("end"); + } + + public static void tryDoWhileFinally(int i) { + System.out.println("start"); + + try { + do { + System.out.println("a"); + i++; + } while (i < 5); + } finally { + System.out.println("b"); + } + + System.out.println("end"); + } +} diff --git a/src/test/resources/java/org/jd/core/test/Enum.java b/src/test/resources/java/org/jd/core/test/Enum.java new file mode 100644 index 00000000..4094f4d7 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Enum.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class Enum { + public enum Day { + SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY + } + + public enum Planet { + MERCURY (3.303e+23, 2.4397e6), + VENUS (4.869e+24, 6.0518e6), + EARTH (5.976e+24, 6.37814e6), + MARS (6.421e+23, 3.3972e6), + JUPITER (1.9e+27, 7.1492e7), + SATURN (5.688e+26, 6.0268e7), + + + URANUS (8.686e+25, 2.5559e7), + + + NEPTUNE (1.024e+26, 2.4746e7); + + private final double mass; // in kilograms + private final double radius; // in meters + + Planet(double mass, double radius) { + this.mass = mass; + this.radius = radius; + } + + private double mass() { return mass; } + private double radius() { return radius; } + + // universal gravitational constant (m3 kg-1 s-2) + public static final double G = 6.67300E-11; + + double surfaceGravity() { + return G * mass / (radius * radius); + } + + double surfaceWeight(double otherMass) { + return otherMass * surfaceGravity(); + } + + public static void main(String[] args) { + if (args.length != 1) { + System.err.println("Usage: java Planet "); + System.exit(-1); + } + double earthWeight = Double.parseDouble(args[0]); + double mass = earthWeight/EARTH.surfaceGravity(); + for (Planet p : Planet.values()) + System.out.printf("Your weight on %s is %f%n", p, p.surfaceWeight(mass)); + } + } + + public enum EmptyEnum {} + + public enum EnumWithAConstructor { + A, B, C; + + protected int i; + + EnumWithAConstructor() { + this.i = 0; + } + } + + public enum EnumWithTwoConstructors { + A, B, C; + + protected int i; + + EnumWithTwoConstructors() { + this.i = 0; + } + + EnumWithTwoConstructors(int i) { + this.i = i; + } + } +} diff --git a/src/test/resources/java/org/jd/core/test/For.java b/src/test/resources/java/org/jd/core/test/For.java new file mode 100644 index 00000000..ba2698ab --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/For.java @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public class For { + + public void simpleFor() { + System.out.println("start"); + + for (int i=0; i<10; i++) { + System.out.println("loop"); + } + + System.out.println("end"); + } + + public void declarationAndFor() { + System.out.println("start"); + + int i; + + for (i=0; i<5; ++i) { + System.out.println("loop"); + } + + System.out.println("end"); + } + + public void initAndForTestUpdate() { + System.out.println("start"); + + int i=0; + + for (; i<10; i++) { + System.out.println("loop"); + } + + System.out.println("end"); + } + + public void forTestUpdate(int i) { + System.out.println("start"); + + for (; i<10; i++) { + System.out.println("loop"); + } + + System.out.println("end"); + } + + public void forInitUpdate() { + System.out.println("start"); + + for (int i=0;; i++) { + System.out.println("loop"); + } + } + + public void forUpdate(int i) { + System.out.println("start"); + + for (;; i++) { + System.out.println("loop"); + } + } + + public void forInitTest() { + System.out.println("start"); + + for (int i=0; i<10;) { + System.out.println("loop"); + } + } + + public void forTest(int i) { + System.out.println("start"); + + for (; i<10;) { + System.out.println("loop"); + } + } + + public void forInit() { + System.out.println("start"); + + for (int i=0;;) { + System.out.println("loop"); + } + } + + public void forInfiniteLoop() { + System.out.println("start"); + + for (;;) { + System.out.println("loop"); + } + } + + public void forMultipleVariables1() { + System.out.println("start"); + + for (int i=0, j=i, size=10; i list) { + System.out.println("start"); + + for (String s : list) + System.out.println(s); + + System.out.println("end"); + } + + public void forTry(int i, Object o) { + System.out.println("start"); + + for (i=0; i<10; i++) { + System.out.println("a"); + try { + System.out.println("b"); + } catch (RuntimeException e) { + System.out.println("c"); + } + } + + System.out.println("end"); + } + + public void forTryReturn(int i, Object o) { + System.out.println("start"); + + for (i=0; i<10; i++) { + System.out.println("a"); + try { + System.out.println("b"); + return; + } catch (RuntimeException e) { + System.out.println("c"); + } + } + + System.out.println("end"); + } + + public Object forFor() { + System.out.println("start"); + + for (int i=0; i<5; ++i) + { + if (this == null) return null; + System.out.println(i); + } + + for (int i : new int[] { 4 }) + { + if (0 == i) + { + System.out.println(i); + } + } + + System.out.println("end"); + + return this; + } + + public void forIf() { + System.out.println("start"); + + for (int i=0; i<10; i++) + { + System.out.println("b"); + if (i == 4) + System.out.println("c"); + System.out.println("d"); + } + + if (this == null) + System.out.println("e"); + + System.out.println("end"); + } + + private static void forAndEmptyDoWhile() { + System.out.println("start"); + + int i; + + for (i=0; i<20; i++) + System.out.println(i); + + do; + while (i < 10); + + System.out.println("end"); + } + + private static void forAndEmptyDoWhileTestOr() { + System.out.println("start"); + + int i; + + for (i=0; i<10; i++) + System.out.println(i); + + do; + while ((i < 20) || (i < 10) || (i < 0)); + + System.out.println("end"); + } + + private static void forAndEmptyDoWhileTestAnd() { + System.out.println("start"); + + int i; + + for (i=0; i<10; i++) + System.out.println(i); + + do; + while ((i < 20) && (i < 10) && (i < 0)); + + System.out.println("end"); + } + + public static void forEachArray(String[] array) { + System.out.println("start"); + + for(String s : array) { + System.out.println(s); + } + + for(String s : array) { + System.out.println(s); + } + + System.out.println("end"); + } + + public static void forEachList(List list) { + System.out.println("start"); + + for(String s : list) { + System.out.println(s); + } + + for(String s : list) { + System.out.println(s); + } + + System.out.println("end"); + } + + public void notAForEach() { + Iterator iterator = Arrays.asList(this.getClass().getInterfaces()).iterator(); + while (iterator.hasNext()) { + Class clazz = iterator.next(); + System.out.println(clazz); + } + + System.out.println(iterator); + } + + public static void forUnderscore(String[] __) { + for (int ___ = 0; ___ < __.length; ___++) + System.out.println(__[___]); + } + + private byte[] forTryReturn() throws Exception + { + for(int i=0; i<3; i++) { + try { + byte[] data = null; + return data; + } catch (Exception e) { + Thread.sleep(300); + } + } + throw new Exception("comm error"); + } + + protected boolean ifForIfReturn(int[] array) { + boolean flag = false; + + if (flag == false) { + for (int i : array) { + if (flag != false) + break; + } + + if (flag == false) { + flag = true; + } + } + + return flag; + } + + public static void forIfContinue() { + System.out.println("start"); + + for (int i=0; i<100; i++) { + System.out.println("a"); + if (i == 0) { + System.out.println("b"); + if (i == 1) { + continue; + } + System.out.println("c"); + } + System.out.println("d"); + } + + System.out.println("end"); + } + + public void forIfIfContinue() { + for (int i=0; i<100; i++) { + if (i == 1) { + // Empty line + if (i != 2) { + continue; + } + } + i += 42; + } + } +} diff --git a/src/test/resources/java/org/jd/core/test/GenericClass.java b/src/test/resources/java/org/jd/core/test/GenericClass.java new file mode 100644 index 00000000..d9dea2ee --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/GenericClass.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.io.Serializable; +import java.security.InvalidParameterException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class GenericClass, // Extends class and two interfaces + T7 extends Map, + T8 extends Map, + T9 extends T8> + extends ListImpl + implements Serializable, Comparable { + + public List> list1 = new ListImpl<>(); + public List> list2; + + public GenericClass() { + super(10); + list2 = new ListImpl<>(); + } + + public void fromArrayToCollection(T[] a, Collection c) { + for (T o : a) { + c.add(o); + } + } + + public void copy(List dest, List src) { + // ... + } + + public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException { + // ... + return null; + } + + public List print(List list) throws T2, InvalidParameterException { + // ... + return null; + } + + public int scopesAndVariables(int i) { + int result; + + List as = new ListImpl<>(i + 1); + System.out.println(as); + + { + int j = i; + String s = "test " + j; + System.out.println(s); + int jj = 123; + System.out.println(jj); + result = 1; + } + { + int k = i; + List l = new ListImpl<>(k + 3); + System.out.println(l); + int kk = 456; + System.out.println(kk); + result = 2; + } + + return result; + } + + public int varargs(int firstParameter, int... lastParameters) { + return firstParameter; + } + + @SuppressWarnings("unchecked") + public > R genericAssignment(int i, int j, String[] envs, String[] opts, String[] args, T t, L l) { + l.add(envs[0]); + + t = (T)opts[1]; + + T tt = t; + + return null; + } + + @Override + public int compareTo(T1 o) { + return 0; + } + + public T1 call() { + return call(0); + } + + @SuppressWarnings("unchecked") + public T1 call(int i) { + return (T1)this; + } +} diff --git a/src/test/resources/java/org/jd/core/test/IfElse.java b/src/test/resources/java/org/jd/core/test/IfElse.java new file mode 100644 index 00000000..b8f149f0 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/IfElse.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class IfElse { + + public void if_() { + System.out.println("start"); + + if (this == null) { + System.out.println("what? 'this' is null?"); + } + + System.out.println("end"); + } + + public void ifCallBoolean() { + System.out.println("start"); + + if ("abc".isEmpty() && "abc".isEmpty()) { + System.out.println("what? 'abc' is empty?"); + } + + System.out.println("end"); + } + + public void ifElse() { + System.out.println("start"); + + if (this == null) { + System.out.println("what? 'this' is null?"); + } else { + System.out.println("whew!"); + } + + System.out.println("end"); + } + + public void ifElseIfElse() { + System.out.println("start"); + + if (this == null) { + System.out.println("what? 'this' is null?"); + } else if (this == null) { + System.out.println("how this message can be written?"); + } else { + System.out.println("whew!"); + } + + System.out.println("end"); + } + + public void ifIf(int i) { + System.out.println("start"); + + if (i == 0) { + + if (i == 1) { + System.out.println("0"); + } + } + + System.out.println("end"); + } + + public void methodCallInIfCondition(int i) { + System.out.println("start"); + + if (i == System.currentTimeMillis()) { + System.out.println("=="); + } else if (i != System.currentTimeMillis()) { + System.out.println("!="); + } else if (i > System.currentTimeMillis()) { + System.out.println(">"); + } else if (i < System.currentTimeMillis()) { + System.out.println("<"); + } else if (i >= System.currentTimeMillis()) { + System.out.println(">="); + } else if (i <= System.currentTimeMillis()) { + System.out.println("<="); + } + + System.out.println("end"); + } + + public void ifORCondition(int i) { + System.out.println("start"); + + if (i==4 || i==5 || i==6) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public void ifANDCondition(int i) { + System.out.println("start"); + + if (i==4 && i==5 && i==6) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public void ifElseORCondition(int i) { + System.out.println("start"); + + if (i==4 || i==5 || i==6) { + System.out.println("a"); + } else { + System.out.println("b"); + } + + System.out.println("end"); + } + + public void ifElseANDCondition(int i) { + System.out.println("start"); + + if (i==4 && i==5 && i==6) { + System.out.println("a"); + } else { + System.out.println("b"); + } + + System.out.println("end"); + } + + public void ANDAndORConditions(int i) { + System.out.println("start"); + + if ((i == 3) || (i == 5) || (i == 6)) + System.out.println("a"); + else if ((i != 4) && (i > 7) && (i > 8)) + System.out.println("b"); + else + System.out.println("c"); + + System.out.println("end"); + } + + public void ifElse6ANDAnd2ORCondition(int i) { + System.out.println("start"); + + if ((i==1 && i==2 && i==3) || (i==4 && i==5 && i==6) || (i==7 && i==8 && i==9)) { + System.out.println("a"); + } else { + System.out.println("b"); + } + + System.out.println("end"); + } + + public void ifElse6ORAnd2ANDCondition(int i) { + System.out.println("start"); + + if ((i==1 || i==2 || i==3) && (i==4 || i==5 || i==6) && (i==7 || i==8 || i==9)) { + System.out.println("a"); + } else { + System.out.println("b"); + } + + System.out.println("end"); + } + + public void ifElseORAndANDConditions(int i) { + System.out.println("start"); + + if ((i==1 || (i==5 && i==6 && i==7) || i==8 || (i==9 && i==10 && i==11)) && (i==4 || (i%200) > 50) && (i>3 || i>4)) { + System.out.println("a"); + } else { + System.out.println("b"); + } + + System.out.println("end"); + } + + public void ifElseANDAndORConditions(int i) { + System.out.println("start"); + + if ((i==1 && (i==5 || i==6 || i==7) && i==8 && (i==9 || i==10 || i==11)) || (i==4 && (i%200) > 50) || (i>3 && i>4)) { + System.out.println("a"); + } else { + System.out.println("b"); + } + + System.out.println("end"); + } + + public void ifThrow() { + System.out.println("start"); + + if (this == null) + throw null; + + System.out.println("end"); + } +} diff --git a/src/test/resources/java/org/jd/core/test/InfiniteLayout.java b/src/test/resources/java/org/jd/core/test/InfiniteLayout.java new file mode 100644 index 00000000..82176cde --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/InfiniteLayout.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class InfiniteLayout { + + public class InnerClass { + protected int innerField1 = 0; + + public void innerMethod(int param1) { + int localVariable1 = param1; + } + + public class InnerInnerClass {} + } + + public static class StaticInnerClass { + protected int innerField1 = 0; + } +} diff --git a/src/test/resources/java/org/jd/core/test/Interface.java b/src/test/resources/java/org/jd/core/test/Interface.java new file mode 100644 index 00000000..6539e9d4 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Interface.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.io.Serializable; + +public interface Interface extends Serializable { + static final long serialVersionUID = 9506606333927795L; + + void hello(); +} \ No newline at end of file diff --git a/src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java b/src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java new file mode 100644 index 00000000..29d7d36f --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.time.DateTimeException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +public interface InterfaceWithDefaultMethods { + void setTime(int hour, int minute, int second); + void setDate(int day, int month, int year); + void setDateAndTime(int day, int month, int year, + int hour, int minute, int second); + LocalDateTime getLocalDateTime(); + + static ZoneId getZoneId (String zoneString) { + try { + return ZoneId.of(zoneString); + } catch (DateTimeException e) { + System.err.println("Invalid time zone: " + zoneString + + "; using default time zone instead."); + return ZoneId.systemDefault(); + } + } + + default ZonedDateTime getZonedDateTime(String zoneString) { + return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); + } +} \ No newline at end of file diff --git a/src/test/resources/java/org/jd/core/test/Lambda.java b/src/test/resources/java/org/jd/core/test/Lambda.java new file mode 100644 index 00000000..57d71683 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Lambda.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.function.*; +import java.util.stream.Collectors; + +public class Lambda { + protected int index; + + public void printListItems1(List list) { + list.forEach(System.out::println); + } + + public void printListItems2(List list) { + list.stream().filter(s -> s != null).forEach(s -> System.out.println(s)); + } + + public void printListItems3(List list, int length) { + Predicate filter = s -> s.length() == length; + Consumer println = s -> System.out.println(s); + + list.stream().filter(filter).forEach(println); + } + + public void printMapItems(List list) { + list.stream() + .collect(Collectors.toMap(lambda -> lambda.index, Function.identity())) + .forEach( + (key, value) -> + System.out.println(key + " --> " + value)); + } + + public void startThread1() { + Thread thread = new Thread(() -> { + System.out.println("hello"); + System.out.println("world"); + }); + + thread.start(); + } + + public void startThread2(String message, int count) { + Thread thread = new Thread(() -> { + for (int i=0; i staticMethodReference = String::valueOf; + BiFunction methodReference = String::compareTo; + Supplier instanceMethodReference = s::toString; + Supplier constructorReference = String::new; + } + + public void methodTypes() { + MethodType mtToString = MethodType.methodType(String.class); + MethodType mtSetter = MethodType.methodType(void.class, Object.class); + MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, String.class); + } +} diff --git a/src/test/resources/java/org/jd/core/test/Layout.java b/src/test/resources/java/org/jd/core/test/Layout.java new file mode 100644 index 00000000..1df0a11f --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Layout.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.io.Serializable; +import java.util.Enumeration; + +public abstract class Layout extends Number implements Serializable, Comparable, Runnable { + protected String str = "str"; + protected int[][] array = { + {0, 1}, + {2, 3, 4} + }; + + protected enum Priority { + LOW(0), HIGH(1); + + private final int level; + + Priority(int level) { + this.level = level; + } + + public int getLevel() { + return level; + } + }; + + public static void main(String[] args) { + int b = 0; + int c = 1; + + if (args == null) { + return; + } + + int i = call( + "aaaa", + b, + new java.util.Enumeration() { + public boolean hasMoreElements() { + return false; + } + + public Object nextElement() { + return null; + } + }, + c); + + System.out.println(i); + + if (i == 2) { + System.out.println('2'); + } else { + System.out.println('?'); + } + + switch (i) { + case 0: + System.out.println('0'); + break; + case 1: + case 2: + System.out.println("1 or 2"); + break; + default: + System.out.println('?'); + break; + } + + System.out.println(i); + + try { + i = 42 / i; + } catch (Exception e) { + e.printStackTrace(); + } + + System.out.println(i); + + do { + i++; + } while (i < 10); + + System.out.println(i); + + while (i > 5) { + i--; + } + + System.out.println(i); + } + + @Override + @Deprecated + public int intValue() { + return 0; + } + + public static native int call(String s, int b, Enumeration e, int c); +} diff --git a/src/test/resources/java/org/jd/core/test/OuterClass.java b/src/test/resources/java/org/jd/core/test/OuterClass.java new file mode 100644 index 00000000..e29b6716 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/OuterClass.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.util.Comparator; + +public class OuterClass { + protected int outerField1 = 0; + protected String[] outerField2 = { "0" }; + protected String[][] outerField3 = { { "0" }, { "1", "2" } }; + + protected Thread thread; + protected Thread.State state; + + public void method(int param1, String[] param2) { + final int localVariable1 = param1; + final String[] localVariable2 = param2; + + InnerClass innerClass = new InnerClass(param1, param2); + innerClass.innerMethod(localVariable1, localVariable2); + + StaticInnerClass staticInnerClass = new StaticInnerClass(param1, param2); + staticInnerClass.innerMethod(localVariable1, localVariable2); + + InnerClass anonymousClass = new InnerClass(param1, param2) { + public void innerMethod(int param1, String... param2) { + innerField1 = param1; + innerField2 = param2; + + outerField1 = param1; + outerField2 = param2; + + innerField1 = localVariable1; + innerField2 = localVariable2; + } + }; + anonymousClass.innerMethod(localVariable1, localVariable2); + + StaticInnerClass staticAnonymousClass = new StaticInnerClass(param1, param2) { + public void innerMethod(int param1, String... param2) { + innerField1 = param1; + innerField2 = param2; + + outerField1 = param1; + outerField2 = param2; + + innerField1 = localVariable1; + innerField2 = localVariable2; + } + }; + staticAnonymousClass.innerMethod(localVariable1, localVariable2); + + InnerEnum.A.innerMethod(localVariable1, localVariable2); + + class LocalClass { + protected int innerField1 = 0; + protected String[] innerField2 = { "0" }; + + public LocalClass(int param1) { + int variable1 = param1; + } + + public LocalClass(int param1, String... param2) { + int variable1 = param1; + String[] variable2 = param2; + + innerField1 = param1; + innerField2 = param2; + + outerField1 = param1; + outerField2 = param2; + + innerField1 = localVariable1; + innerField2 = localVariable2; + } + + public void localMethod(int param1, String... param2) { + int variable1 = param1; + String[] variable2 = param2; + + innerField1 = param1; + innerField2 = param2; + + outerField1 = param1; + outerField2 = param2; + + innerField1 = localVariable1; + innerField2 = localVariable2; + } + }; + + LocalClass localClass = new LocalClass(param1, param2); + localClass.localMethod(localVariable1, localVariable2); + } + + public class InnerClass { + protected int innerField1 = 0; + protected String[] innerField2 = { "0" }; + + public InnerClass(int param1, String... param2) { + int localVariable1 = param1; + String[] localVariable2 = param2; + + innerField1 = param1; + innerField2 = param2; + + outerField1 = param1; + outerField2 = param2; + } + + public InnerClass(String s, int param1, String... param2) { + this(param1, param2); + System.out.println(s); + } + + public void innerMethod(int param1, String... param2) { + int localVariable1 = param1; + String[] localVariable2 = param2; + + outerField1 = param1; + outerField2 = param2; + + method(0, null); + } + + public class InnerInnerClass {} + } + + public static class StaticInnerClass { + protected int innerField1 = 0; + protected String[] innerField2 = { "0" }; + + public StaticInnerClass(int param1, String... param2) { + int localVariable1 = param1; + String[] localVariable2 = param2; + + innerField1 = param1; + innerField2 = param2; + } + + public StaticInnerClass(String s, int param1, String... param2) { + this(param1, param2); + System.out.println(s); + } + + public void innerMethod(int param1, String... param2) { + int localVariable1 = param1; + String[] localVariable2 = param2; + + innerField1 = param1; + innerField2 = param2; + } + } + + public enum InnerEnum { + A, B, C; + + public void innerMethod(int param1, String... param2) { + int localVariable1 = param1; + String[] localVariable2 = param2; + } + } + + public static class NumberComparator implements Comparator { + @Override + public int compare(Number o1, Number o2) { + return o2.intValue() - o1.intValue(); + } + } + + public static class SafeNumberComparator extends NumberComparator { + @Override + public int compare(Number o1, Number o2) { + if (o1 == null) { + return (o2 == null) ? 0 : 1; + } + if (o2 == null) { + return -1; + } + return super.compare(o1, o2); + } + } +} diff --git a/src/test/resources/java/org/jd/core/test/Switch.java b/src/test/resources/java/org/jd/core/test/Switch.java new file mode 100644 index 00000000..ac908af7 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Switch.java @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class Switch { + + public void simpleSwitch(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + break; + case 3: + System.out.println("3"); + break; + } + + System.out.println("end"); + } + + public void switchFirstBreakMissing(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + case 1: + System.out.println("1"); + break; + case 3: + System.out.println("3"); + break; + } + + System.out.println("end"); + } + + public void switchSecondBreakMissing(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + default: + System.out.println("3"); + break; + } + + System.out.println("end"); + } + + public void switchDefault(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + case 1: + System.out.println("1"); + break; + case 3: + System.out.println("3"); + break; + default: + System.out.println("?"); + break; + } + + System.out.println("end"); + } + + public void lookupSwitchDefault(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + case 1: + System.out.println("1"); + break; + case 30: + System.out.println("30"); + break; + default: + System.out.println("?"); + break; + } + + System.out.println("end"); + } + + public void switchOneExitInFirstCase(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + throw new RuntimeException("boom"); + default: + System.out.println("3"); + return; + } + + System.out.println("end"); + } + + public void switchOneExitInSecondCase(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + return; + case 1: + System.out.println("1"); + break; + default: + System.out.println("3"); + return; + } + + System.out.println("end"); + } + + public void switchOneExitInLastCase(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + return; + case 1: + System.out.println("1"); + return; + default: + System.out.println("3"); + break; + } + + System.out.println("end"); + } + + public void testSwitch() { + System.out.println("start"); + + switch ((int) (System.currentTimeMillis() & 0xF)) { + case 0: + System.out.println("0"); + case 1: + System.out.println("0 or 1"); + break; + case 2: + default: + System.out.println("2 or >= 9"); + break; + case 3: + case 4: + System.out.println("3 or 4"); + break; + case 5: + System.out.println("5"); + break; + case 6: + System.out.println("6"); + break; + case 7: + System.out.println("7"); + break; + case 8: + System.out.println("8"); + break; + } + + System.out.println("end"); + } + + public void complexSwitch(int i) { + System.out.println("start"); + + switch (i % 4) { + case 1: + System.out.println("1"); + switch (i * 2) { + case 2: + System.out.println("1.2"); + break; + case 10: + System.out.println("1.10"); + default: + System.out.println("1.?"); + } + break; + case 2: + switch (i * 3) { + case 6: + System.out.println("2.6"); + case 18: + System.out.println("2.18"); + default: + System.out.println("2.?"); + } + System.out.println("2"); + default: + switch (i * 7) { + case 0: + System.out.println("?.0"); + break; + case 7: + System.out.println("?.7"); + default: + System.out.println("?.?"); + } + System.out.println("?"); + } + + System.out.println("end"); + } + + public void emptySwitch(int i) { + System.out.println("start"); + + switch (i) {} + + System.out.println("end"); + } + + public void switchOnLastPosition(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + break; + case 3: + System.out.println("3"); + break; + } + } + + public void switchBreakDefault(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + break; + default: + System.out.println("default"); + break; + } + + System.out.println("end"); + } + + public void switchBreakBreakDefault(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + break; + case 1: + case 2: + case 3: + break; + case 4: + case 5: + default: + System.out.println("default"); + break; + } + + System.out.println("end"); + } + + public void switchFirstIfBreakMissing(int i) { + System.out.println("start"); + + switch (i) { + case 0: + System.out.println("0"); + if (i != 1) + break; + case 1: + System.out.println("1"); + break; + case 3: + System.out.println("3"); + break; + } + + System.out.println("end"); + } +} diff --git a/src/test/resources/java/org/jd/core/test/Synchronized.java b/src/test/resources/java/org/jd/core/test/Synchronized.java new file mode 100644 index 00000000..f5b439d7 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/Synchronized.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class Synchronized +{ + public int methodSynchronized(StringBuilder paramStringBuilder) + { + synchronized (paramStringBuilder) + { + inSynchronized(); + } + return 2; + } + + public int methodSynchronized2(StringBuilder paramStringBuilder) + { + synchronized (paramStringBuilder) + { + inSynchronized(); + return 2; + } + } + + public void methodSynchronized3(StringBuilder paramStringBuilder) + { + synchronized (paramStringBuilder) + { + inSynchronized(); + return; + } + } + + public void methodSynchronized4(StringBuilder paramStringBuilder) + { + synchronized (paramStringBuilder) + { + if (paramStringBuilder == null) + throw new RuntimeException(); + } + } + + public int methodSynchronized5(StringBuilder paramStringBuilder) + { + before(); + + synchronized (paramStringBuilder) + { + inSynchronized(); + } + + after(); + return 2; + } + + public int methodSynchronized6(StringBuilder paramStringBuilder) + { + before(); + + synchronized (paramStringBuilder) + { + inSynchronized(); + return 2; + } + } + + public void methodSynchronized7(StringBuilder paramStringBuilder) + { + before(); + + synchronized (paramStringBuilder) + { + inSynchronized(); + throw new RuntimeException(); + } + } + + public void methodSynchronized8(StringBuilder paramStringBuilder) + { + before(); + + synchronized (paramStringBuilder) + { + if (paramStringBuilder == null) + throw new RuntimeException(); + } + + after(); + } + + public boolean contentEquals1(String s) + { + synchronized(s) + { + return subContentEquals(s); + } + } + + public boolean contentEquals2(String s) + { + synchronized(s) + { + s += "z"; + return subContentEquals(s); + } + } + + public boolean contentEquals3(String s) + { + synchronized(s) + { + s += "z"; + } + return subContentEquals(s); + } + + public void methodIfIfSynchronized() + { + if (this == null) + { + if (this != null) + { + System.out.println("1\\2"); + + synchronized (this) + { + System.out.println("2"); + } + } + else + { + System.out.println("3"); + } + } + } + + public boolean subContentEquals(String s) + { + return (s == null); + } + + private void before() + { + } + + private void inSynchronized() + { + } + + private void after() + { + } +} diff --git a/src/test/resources/java/org/jd/core/test/TernaryOperator.java b/src/test/resources/java/org/jd/core/test/TernaryOperator.java new file mode 100644 index 00000000..98a704b2 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/TernaryOperator.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class TernaryOperator { + protected String str = "str"; + + public void ternaryOperator(String s) { + System.out.println("start"); + + str = + (s == null) ? + "1" : + "2"; + + System.out.println("end"); + } + + public void ternaryOperatorsInTernaryOperator(String s) { + System.out.println("start"); + + s = (s==null) ? ((s==null) ? "1" : "2") : ((s==null) ? "3" : "4"); + + System.out.println("end"); + } + + public boolean ternaryOperatorsInReturn(String s) { + System.out.println("start"); + + long time = System.currentTimeMillis(); + + return (s == s) && (time >= time); + } + + public void ternaryOperatorInIf1(String s1, String s2) { + System.out.println("start"); + + if ((s1 == null) ? (s2 == null) : s1.equals(s2)) + System.out.println("a"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElse0(String s1, String s2) { + System.out.println("start"); + + if ((s1 != null) && (s1.length() > 0)) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElse1(String s1, String s2) { + System.out.println("start"); + + if ((s1 == null) ? (s2 == null) : s1.equals(s2)) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElse2(String s1, String s2) { + System.out.println("start"); + + if ((s1 == null) ? false : (s1.length() > 0)) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElse3(String s1, String s2) { + System.out.println("start"); + + if ((s1 != null) ? (s1.length() > 0) : false) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElse4(String s1, String s2) { + System.out.println("start"); + + if ((s1 == null) ? s1.equals(s2) : (s2 == null)) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElse5(String s1, String s2) { + System.out.println("start"); + + if ((s1 == null) ? (s2 == null) : (s1 + s2 == null)) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElse6(String s1, String s2) { + System.out.println("start"); + + if ((s1 == null) ? ((s2 == null) ? (s1 != null) : (s2 != null)) : ((s1 + s2 == null) ? (s1 != null) : (s2 != null))) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElseFalse(String s1, String s2) { + System.out.println("start"); + + if ((s1 == null) ? false : false) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElseANDCondition(String s1, String s2) { + System.out.println("start"); + + if ((s1 == s2) && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && (s1 == s2)) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public void ternaryOperatorInIfElseORCondition(String s1, String s2) { + System.out.println("start"); + + if ((s1 == s2) || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || (s1 == s2)) + System.out.println("a"); + else + System.out.println("b"); + + System.out.println("end"); + } + + public String castTernaryOperator() { + return Short.toString((short)((this == null) ? 1 : 2)); + } +} diff --git a/src/test/resources/java/org/jd/core/test/TryCatchFinally.java b/src/test/resources/java/org/jd/core/test/TryCatchFinally.java new file mode 100644 index 00000000..8dc5a141 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/TryCatchFinally.java @@ -0,0 +1,932 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class TryCatchFinally +{ + public void methodTryCatch() { + before(); + + try { + inTry(); + if (this == null) + inTry(); + } catch (RuntimeException runtimeexception) { + runtimeexception.printStackTrace(); + inCatch1(); + } + + after(); + } + + public void methodTryCatchCatch() { + before(); + + try { + inTry(); + } catch (RuntimeException runtimeexception) { + inCatch1(); + runtimeexception.printStackTrace(); + } catch (Exception exception) { + inCatch2(); + } + + after(); + } + + public void methodTryCatchCatchOneExitInTry() { + before(); + + try { + inTry(); + } catch (RuntimeException runtimeexception) { + inCatch1(); + throw new RuntimeException(); + } catch (Exception exception) { + inCatch2(); + return; + } + + after(); + } + + public void methodTryCatchCatchOneExitInFirstCatch() { + before(); + + try { + inTry(); + return; + } catch (RuntimeException runtimeexception) { + inCatch1(); + } catch (Exception exception) { + inCatch2(); + return; + } + + after(); + } + + public void methodTryCatchCatchOneExitInLastCatch() { + before(); + + try { + inTry(); + return; + } catch (RuntimeException runtimeexception) { + inCatch1(); + return; + } catch (Exception exception) { + inCatch2(); + } + + after(); + } + + public void methodTrySwitchFinally() throws Exception { + System.out.println("start"); + + try { + System.out.println("in try"); + + switch ((int)(System.currentTimeMillis() & 0xF)) { + case 0: + System.out.println("0"); + break; + default: + System.out.println("default"); + break; + } + } finally { + System.out.println("in finally"); + } + + System.out.println("end"); + } + + public void methodTryFinally1() { + before(); + + try { + inTry(); + } finally { + inFinally(); + } + + after(); + } + + public void methodTryFinally2() { + before(); + + try { + inTry(); + return; + } finally { + inFinally(); + } + } + + public void methodTryFinally3() { + before(); + + try { + inTry(); + throw new RuntimeException(); + } finally { + inFinally(); + } + } + + public long methodTryCatchFinallyReturn() { + before(); + + try { + inTry(); + + return + System.currentTimeMillis(); + } catch (RuntimeException e) { + inCatch1(); + + return + System.currentTimeMillis(); + } finally { + inFinally(); + } + } + + public long methodTryFinallyReturn() { + before(); + + try { + inTry(); + + return System.currentTimeMillis(); + } finally { + inFinally(); + } + } + + public void methodTryFinally4() { + before(); + + try { + inTry(); + if (this == null) + return; + } finally { + inFinally(); + System.out.println("ee"); + } + + after(); + } + + public void methodEmptyTryCatch() { + before(); + + try { + System.out.println("try"); + } catch (RuntimeException e) { + // Empty + } + + after(); + } + + public void methodEmptyTryFinally() { + before(); + + try { + System.out.println("try"); + } finally { + // Empty + } + + after(); + } + + public void methodTryCatchFinally1() { + before(); + + try { + inTry(); + } catch (RuntimeException runtimeexception) { + inCatch1(); + } finally { + inFinally(); + } + + after(); + } + + public void methodTryCatchFinally2() { + before(); + + try { + inTry(); + } catch (RuntimeException runtimeexception) { + inCatch1(); + if (this == null) + return; + inCatch2(); + } finally { + inFinally(); + System.out.println("ee"); + } + + after(); + } + + public int methodTryCatchFinally3() { + before(); + + try { + inTry(); + } catch (RuntimeException e) { + inCatch1(); + } catch (Exception e) { + inCatch2(); + return 1; + } finally { + inFinally(); + new RuntimeException(); + } + + after(); + return 2; + } + + public int methodTryCatchFinally4() { + before(); + + try { + inTry(); + throw new Exception(); + } catch (Exception e) { + inCatch2(); + } finally { + inFinally(); + } + + after(); + return 2; + } + + public void methodTryCatchFinally5() throws Exception { + System.out.println("start"); + + try { + System.out.println("in try"); + + if (this == null) + return; + if (this == null) + throw new RuntimeException(); + + // throw new Exception(); // + return; + } catch (RuntimeException e) { + System.out.println("in catch"); + + if (this == null) + return; + if (this == null) + throw new RuntimeException(); + + System.out.println("in catch"); + } finally { + System.out.println("in finally"); + } + + System.out.println("end"); + } + + public int methodTryCatchFinallyInTryCatchFinally() throws Exception { + System.out.println("start"); + + int a = 1; + int b = 1; + + try { + System.out.println("in try"); + + try { + System.out.println("in inner try"); + + if (this == null) { + System.out.println("before throw in inner try"); + throw new RuntimeException(); + } + + return b; + } catch (RuntimeException e) { + System.out.println("in catch in inner try"); + + if (this == null) + throw new RuntimeException(); + + System.out.println("in catch in inner try"); + } finally { + for (int i=0; i<10; i++) + System.out.println("in finally in inner try"); + } + + System.out.println("in try"); + + try { + System.out.println("in inner try"); + + if (this == null) { + System.out.println("before throw in inner try"); + throw new RuntimeException(); + } + + return b; + } catch (RuntimeException e) { + System.out.println("in catch in inner try"); + + if (this == null) + throw new RuntimeException(); + + System.out.println("in catch in inner try"); + } finally { + for (int i=0; i<10; i++) + System.out.println("in finally in inner try"); + } + + System.out.println("in try"); + } finally { + for (int i=0; i<10; i++) + System.out.println("in finally"); + } + + System.out.println("end"); + + return a + b; + } + + public void methodTryCatchCatchFinally() { + before(); + + try { + inTry(); + } catch (RuntimeException e) { + inCatch1(); + } catch (Exception e) { + inCatch2(); + } finally { + inFinally(); + } + + after(); + } + + public void methodTryCatchCatchCatchFinally() { + before(); + + try { + inTry(); + } catch (ClassCastException classcastexception) { + inCatch1(); + } catch (RuntimeException runtimeexception) { + inCatch2(); + } catch (Exception exception) { + inCatch3(); + } finally { + inFinally(); + } + after(); + } + + public void methodTryTryReturnFinallyFinally() { + before(); + + try { + try { + inTryA(); + return; + } finally { + inFinallyA(); + } + } finally { + inFinally(); + } + } + + public void methodTryTryReturnFinallyCatchFinally() { + before(); + + try { + try { + inTry(); + return; + } finally { + inFinally(); + } + } catch (ClassCastException classcastexception) { + try { + inTryA(); + return; + } finally { + inFinallyA(); + } + } catch (RuntimeException runtimeexception) { + } catch (Exception exception) { + try { + inTryC(); + return; + } finally { + inFinallyC(); + } + } finally { + inFinally(); + } + } + + public void methodTryTryFinallyFinallyTryFinally() { + before(); + + try { + try { + inTry(); + } finally { + inFinally(); + } + } finally { + try { + inTryC(); + } finally { + inFinallyC(); + } + } + + after(); + } + + public void methodTryTryFinallyFinallyTryFinallyReturn() { + before(); + + try { + try { + inTry(); + if (this == null) + return; + } finally { + inFinally(); + if (this == null) + return; + } + } finally { + try { + inTryC(); + if (this == null) + return; + } finally { + inFinallyC(); + if (this == null) + return; + } + } + + after(); + } + + public void methodIfIfTryCatch() { + if (this == null) { + if (this != null) { + System.out.println("if if"); + + try { + System.out.println("if if try"); + } catch (Exception ex) { + ex.printStackTrace(); + throw new RuntimeException(ex.getMessage()); + } + } else { + System.out.println("if else"); + } + } + } + + public void methodIfIfTryFinally() { + if (this == null) { + if (this != null) { + System.out.println("if if"); + + try { + System.out.println("if if try"); + } finally { + System.out.println("if if finally"); + } + } else { + System.out.println("if else"); + } + } + } + + public Object testBug155(Object obj) { + try { + if (obj != null) + return obj; + } catch (Exception e) { + } + + return obj; + } + + public void testBugLdapUtil(int i) { + System.out.println("a"); + + if ((i < 0) && (i > 4)) { + try { + if (i == 0) { + System.out.println("b"); + } else { + System.out.println("c"); + } + } catch (RuntimeException e) { + System.out.println("d"); + } + } + + if ((i < 2) && (i < 6)) { + System.out.println("e"); + } + } + + public int methodTryCatch2() { + before(); + + try { + inTry(); + return 1; + } catch (RuntimeException e) { + e.printStackTrace(); + inCatch1(); + return 2; + } + } + + public int methodTryCatch3() { + before(); + + try { + inTry(); + return 1; + } catch (RuntimeException e) { + e.printStackTrace(); + inCatch1(); + } + + return 2; + } + + public int methodTryCatch4() { + before(); + + try { + inTry(); + throw new RuntimeException("t"); + } catch (RuntimeException e) { + e.printStackTrace(); + inCatch1(); + return 2; + } + } + + public int methodTryCatch5() { + before(); + + try { + return 1; + } catch (RuntimeException e) { + inCatch1(); + } + + after(); + return 2; + } + + public int methodTryCatchCatch2() { + before(); + + try { + inTry(); + return 1; + } catch (RuntimeException e) { + inCatch1(); + return 2; + } catch (Exception e) { + inCatch2(); + return 3; + } + } + + public void methodTryCatchCatch3() { + before(); + + try { + inTry(); + throw new RuntimeException("t"); + } catch (RuntimeException e) { + inCatch1(); + throw new RuntimeException("1"); + } catch (Exception e) { + inCatch2(); + throw new RuntimeException("2"); + } + } + + public int methodTryCatchCatch4() { + before(); + + try { + inTry(); + throw new RuntimeException("t"); + } catch (RuntimeException e) { + inCatch1(); + throw new RuntimeException("1"); + } catch (Exception e) { + inCatch2(); + return 3; + } + } + + public int methodTryCatchCatch5() { + before(); + + try { + inTry(); + } catch (RuntimeException e) { + return 1; + } catch (Exception e) { + inCatch2(); + } + + after(); + return 2; + } + + public int methodTryCatchCatch6() { + before(); + + try { + inTry(); + } catch (RuntimeException e) { + inCatch1(); + } catch (Exception e) { + return 1; + } + + after(); + return 2; + } + + public void methodTryFinally() { + before(); + + try { + inTry(); + } finally { + inFinally(); + } + + after(); + } + + public void methodEmptyTryCatch2() { + before(); + + try { + } catch (RuntimeException e) { + new RuntimeException(); + } + + after(); + } + + public void methodTryCatchFinally() { + before(); + + try { + inTry(); + } catch (RuntimeException e) { + inCatch1(); + } finally { + inFinally(); + } + + after(); + } + + public int methodTryCatchCatchFinally3() { + before(); + + int a = 1; + int b = 1; + int c = 1; + int d = 1; + int f = 1; + + try { + inTry(); + } catch (RuntimeException e) { + return 1; + } catch (Exception e) { + return 2; + } finally { + inFinally(); + } + + after(); + return 3; + } + + public int methodTryCatchCatchCatchFinally3() { + before(); + + try { + inTry(); + } catch (ClassCastException e) { + return 1; + } catch (RuntimeException e) { + return 2; + } catch (Exception e) { + inCatch3(); + } finally { + inFinally(); + } + + after(); + return 3; + } + + public int methodTryCatchCatchCatchFinally4() { + before(); + + try { + inTry(); + } catch (ClassCastException e) { + inCatch1(); + } catch (RuntimeException e) { + return 1; + } catch (Exception e) { + return 2; + } finally { + inFinally(); + } + + after(); + return 3; + } + + private Object methodTryCatchTryCatchThrow() throws Exception { + try { + return null; + } catch (Exception e) { + if (this != null) { + try { + return null; + } catch (Exception e2) { + } + } + throw e; + } + } + + public void complexMethodTryCatchCatchFinally() { + before(); + + try { + try { + inTry(); + } catch (RuntimeException runtimeexception) { + inCatch1(); + } catch (Exception exception) { + inCatch2(); + } finally { + inFinally(); + } + } catch (RuntimeException runtimeexception1) { + try { + inTryA(); + } catch (RuntimeException runtimeexception2) { + inCatch1A(); + } catch (Exception exception3) { + inCatch2A(); + } finally { + inFinallyA(); + } + } catch (Exception exception1) { + try { + inTryB(); + } catch (RuntimeException runtimeexception3) { + inCatch1B(); + } catch (Exception exception4) { + inCatch2B(); + } finally { + inFinallyB(); + } + } finally { + try { + inTryC(); + } catch (RuntimeException runtimeexception4) { + inCatch1C(); + } catch (Exception exception8) { + inCatch2C(); + } finally { + inFinallyC(); + } + } + + after(); + } + + public void complexMethodTryFinally() throws Exception { + try { + System.out.println("1"); + + try { + System.out.println("2"); + } catch (Exception e) { + try { + System.out.println("3"); + } catch (Exception e1) { + throw new Exception("Rebuild failed: " + e.getMessage() + "; Original message: " + e1.getMessage()); + } + } + + try { + System.out.println("4"); + } catch (RuntimeException e) { + System.out.println("5"); + } + + System.out.println("6"); + + try { + System.out.println("7"); + } catch (Exception e) { + } + } finally { + try { + System.out.println("8"); + } catch (Exception e) { + throw e; + } + } + return; + } + + public void complexMethodTryCatchCatchFinally3() throws Exception { + try { + System.out.println("1"); + + try { + System.out.println("2"); + } catch (Exception e) { + System.out.println("3"); + } + } finally { + System.out.println("8"); + } + + return; + } + + public boolean subContentEquals(String s) + { + return (s == null); + } + + private void before() {} + + private void inTry() {} + private void inCatch1() {} + private void inCatch2() {} + private void inCatch3() {} + private void inFinally() {} + + private void inTryA() {} + private void inCatch1A() {} + private void inCatch2A() {} + private void inFinallyA() {} + + private void inTryB() {} + private void inCatch1B() {} + private void inCatch2B() {} + private void inFinallyB() {} + + private void inTryC() {} + private void inCatch1C() {} + private void inCatch2C() {} + private void inFinallyC() {} + + private void after() {} +} diff --git a/src/test/resources/java/org/jd/core/test/TryCatchMultiExceptions.java b/src/test/resources/java/org/jd/core/test/TryCatchMultiExceptions.java new file mode 100644 index 00000000..d7521112 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/TryCatchMultiExceptions.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class TryCatchMultiExceptions { + + public void methodTryMultiCatchCatchCatchFinally() { + before(); + + try { + inTry(); + } catch (ClassCastException | ArithmeticException | NullPointerException exception) { + inCatch1(); + } catch (RuntimeException runtimeexception) { + inCatch2(); + } catch (Exception exception) { + inCatch3(); + } finally { + inFinally(); + } + + after(); + } + + private void before() {} + + private void inTry() {} + private void inCatch1() {} + private void inCatch2() {} + private void inCatch3() {} + private void inFinally() {} + + private void after() {} +} diff --git a/src/test/resources/java/org/jd/core/test/TryWithResources.java b/src/test/resources/java/org/jd/core/test/TryWithResources.java new file mode 100644 index 00000000..5d72fad1 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/TryWithResources.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +import java.io.*; + +public class TryWithResources { + + public void try1Resource(String path) throws IOException { + try(FileInputStream input = new FileInputStream(path)) { + int data = input.read(); + + while(data != -1) { + System.out.print((char) data); + data = input.read(); + } + } + } + + public void tryCatch1Resource(String path) { + try(FileInputStream input = new FileInputStream(path)) { + int data = input.read(); + + while(data != -1) { + System.out.print((char) data); + data = input.read(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void tryFinally1Resource(String path) throws IOException { + try(FileInputStream input = new FileInputStream(path)) { + int data = input.read(); + + while(data != -1) { + System.out.print((char) data); + data = input.read(); + } + } finally { + System.out.println("finally"); + } + } + + public void tryCatchFinally1Resource(String path) { + try(FileInputStream input = new FileInputStream(path)) { + int data = input.read(); + + while(data != -1) { + System.out.print((char) data); + data = input.read(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + System.out.println("finally"); + } + } + + public void try2Resources(String pathIn, String pathOut) throws IOException { + try(FileInputStream input = new FileInputStream(pathIn); + FileOutputStream output = new FileOutputStream(pathOut)) { + int data = input.read(); + + while(data != -1) { + output.write(data); + data = input.read(); + } + } + } + + public void tryCatch2Resources(String pathIn, String pathOut) { + try(FileInputStream input = new FileInputStream(pathIn); + FileOutputStream output = new FileOutputStream(pathOut)) { + int data = input.read(); + + while(data != -1) { + output.write(data); + data = input.read(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void tryFinally2Resources(String pathIn, String pathOut) throws IOException { + try(FileInputStream input = new FileInputStream(pathIn); + FileOutputStream output = new FileOutputStream(pathOut)) { + int data = input.read(); + + while(data != -1) { + output.write(data); + data = input.read(); + } + } finally { + System.out.println("finally"); + } + } + + public void tryCatchFinally2Resources(String pathIn, String pathOut) { + try(FileInputStream input = new FileInputStream(pathIn); + FileOutputStream output = new FileOutputStream(pathOut)) { + int data = input.read(); + + while(data != -1) { + output.write(data); + data = input.read(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + System.out.println("finally"); + } + } + + public int tryCatchFinally4Resources(String pathIn, String pathOut) throws Exception { + try { + try (FileInputStream input = new FileInputStream(pathIn); + BufferedInputStream bufferedInput = new BufferedInputStream(input); + FileOutputStream output = new FileOutputStream(pathOut); + BufferedOutputStream bufferedOutput = new BufferedOutputStream(output)) { + int data = bufferedInput.read(); + + while(data != -1) { + bufferedOutput.write(data); + data = bufferedInput.read(); + } + + if (data == -7) { + return 1; + } + + try { + System.out.println("in try"); + } finally { + System.out.println("in finally"); + } + + return 2; + } catch (ClassCastException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + System.out.println("finally, before loop"); + for (int i=0; i<10; i++) { + System.out.println("finally " + i); + } + System.out.println("finally, after loop"); + } + } finally { + System.out.println("finally"); + } + + return 3; + } +} diff --git a/src/test/resources/java/org/jd/core/test/While.java b/src/test/resources/java/org/jd/core/test/While.java new file mode 100644 index 00000000..32389682 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/While.java @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test; + +public class While { + + public void simpleWhile(int i) { + System.out.println("start"); + + while (i-- > 0) { + System.out.println("loop"); + } + + System.out.println("end"); + } + + public void whileTry(int i, Object o) { + while (i<10) { + System.out.println("a"); + try + { + System.out.println("b"); + } + catch (RuntimeException e) + { + System.out.println("c"); + } + } + } + + public void whileTryThrow(int i0) throws Exception { + int $i1 = 1; + + if ($i1 == 2) + throw new Exception("2"); + + while (i0 > 20) + { + try + { + $i1 = i0; + i0 = i0 -1; + System.out.println($i1); + + if ($i1 == 3) + throw new Exception("3"); + } + catch (RuntimeException $r3) + { + System.out.println("RuntimeException caught: " + $r3); + } + } + + return; + } + + public void loop3() { + int i = 0; + + while (i<5) + { + System.out.println(i); + ++i; + } + } + + public void whileThrow() { + System.out.println("a"); + int i = 0; + + while (i < 10) + { + System.out.println("b"); + i++; + + if (i == 3) + throw new RuntimeException(); + } + + System.out.println("c"); + } + + public void whileReturn() { + System.out.println("a"); + int i = 0; + + while (i < 10) + { + System.out.println("b"); + i++; + + if (i == 3) + return; + } + + System.out.println("c"); + } + + public void whileIfContinue() { + System.out.println("a"); + int i = 0; + + while (i > 0) + { + System.out.println("b"); + i++; + if (i > 5) + continue; + System.out.println("bb"); + } + System.out.println("c"); + } + + public void whileIfBreak() { + System.out.println("a"); + int i = 0; + + while (i > 0) + { + System.out.println("b"); + i++; + if (i > 8) + break; + System.out.println("bb"); + } + System.out.println("c"); + } + + public void whileIfContinueBreak() { + System.out.println("a"); + int i = 0; + + while (i > 0) + { + System.out.println("b"); + i++; + if (i > 5) + continue; + if (i > 8) + break; + if (i > 10) + break; + System.out.println("bb"); + } + System.out.println("c"); + } + + public void whileTrue() { + System.out.println("a"); + int i = 0; + + while (true) + { + System.out.println("b"); + i++; + if (i > 5) + continue; + if (i > 8) + break; + if (i > 10) + break; + System.out.println("bb"); + } + + System.out.println("c"); + } + + public void whileTrueIf() { + int i=0; + + System.out.println("a"); + + while (true) + { + System.out.println("b"); + if (i == 4) + { + for (int j=0; j<10; j++) + System.out.println("c"); + break; + } + else if (i == 5) + { + System.out.println("d"); + continue; + } + else if (i == 6) + { + System.out.println("e"); + break; + } + System.out.println("f"); + i++; + } + + System.out.println("g"); + + switch (i) + { + case 1: + System.out.println("h"); + case 2: + System.out.println("i"); + break; + case 3: + System.out.println("j"); + } + + System.out.println("k"); + } + + private void whileWhile() { + int a = 2; + int b = 2; + + while (a>0) { + while (b>0) { + a--; + b--; + } + } + } + + private static void whileTestPreInc() { + int i = 0; + + while (++i < 10) + { + System.out.println("1"); + } + } + + private static void whilePreInc() { + int i = 0; + + while (i < 10) + { + System.out.println("2"); + ++i; + } + } + + private static void whileTestPostInc() { + int i = 0; + + while (i++ < 10) + { + System.out.println("1"); + } + } + + private static void whilePostInc() { + int i = 0; + + while (i < 10) + { + System.out.println("2"); + i++; + } + } + + public void whileANDCondition(int i) { + System.out.println("start"); + + while ((i==4) && (i==5) && (i==6)) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public void whileORAndANDConditions(int i) { + System.out.println("start"); + + while ((i==1 || (i==5 && i==6 && i==7) || i==8 || (i==9 && i==10 && i==11)) && (i==4 || (i%200) > 50) && (i>3 || i>4)) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public void whileAndANDConditions(int i) + { + System.out.println("start"); + + while ((i==1 && (i==5 || i==6 || i==7) && i==8 && (i==9 || i==10 || i==11)) || (i==4 && (i%200) > 50) || (i>3 && i>4)) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public static int whileContinueBreak(int[] array) { + int i = 0; + int length = array.length; + int counter = 0; + + while (i < length) { + int item = array[i]; + + if (item % 2 == 1) { + counter++; + continue; + } + + i++; + break; + } + + i++; + + return counter; + } + + public static void twoWiles() { + int i = 0; + + while (i < 5) { + i++; + } + + while (i < 10) { + i++; + } + + i++; + } + + public static void whileSwitch() { + System.out.println("start"); + + int i = 0; + + while (i++ < 10) { + System.out.println("a"); + + switch (i) { + case 1: + System.out.println('1'); + break; + case 2: + System.out.println('2'); + break; + case 3: + System.out.println('3'); + break; + } + } + + System.out.println("end"); + } + + public static void whileSwitchDefault() { + System.out.println("start"); + + int i = 0; + + while (i++ < 10) { + System.out.println("a"); + + switch (i) { + case 1: + System.out.println('1'); + break; + case 2: + System.out.println('2'); + break; + case 3: + System.out.println('3'); + break; + default: + System.out.println("default"); + break; + } + } + + System.out.println("end"); + } + + public static void whileTryFinally(int i) { + System.out.println("start"); + + while (i < 5) { + try { + System.out.println("a"); + } finally { + i++; + } + } + + System.out.println("end"); + } + + public static void tryWhileFinally(int i) { + System.out.println("start"); + + try { + while (i < 5) { + System.out.println("a"); + i++; + } + } finally { + System.out.println("b"); + } + + System.out.println("end"); + } + + public static void infiniteWhileTryFinally(int i) { + System.out.println("start"); + + while (true) { + try { + System.out.println("a"); + } finally { + i++; + } + } + } + + public static void tryInfiniteWhileFinally(int i) { + System.out.println("start"); + + try { + while (true) { + System.out.println("a"); + } + } finally { + System.out.println("b"); + } + } +} diff --git a/src/test/resources/java/org/jd/core/test/annotation/Author.java b/src/test/resources/java/org/jd/core/test/annotation/Author.java new file mode 100644 index 00000000..e773a0f8 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/annotation/Author.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test.annotation; + +public @interface Author { + Name value(); + Name[] contributors() default {}; +} diff --git a/src/test/resources/java/org/jd/core/test/annotation/Name.java b/src/test/resources/java/org/jd/core/test/annotation/Name.java new file mode 100644 index 00000000..4fe150c0 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/annotation/Name.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test.annotation; + +public @interface Name { + String salutation() default ""; // Salutation + String value(); // First name + String last() default ""; // Last name +} diff --git a/src/test/resources/java/org/jd/core/test/annotation/Quality.java b/src/test/resources/java/org/jd/core/test/annotation/Quality.java new file mode 100644 index 00000000..8dbcfe7b --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/annotation/Quality.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test.annotation; + +public @interface Quality { + enum Level { LOW, MIDDLE, HIGH } + + Level value(); +} diff --git a/src/test/resources/java/org/jd/core/test/annotation/Value.java b/src/test/resources/java/org/jd/core/test/annotation/Value.java new file mode 100644 index 00000000..7f8cb007 --- /dev/null +++ b/src/test/resources/java/org/jd/core/test/annotation/Value.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.test.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +public @interface Value { + boolean z() default true; + byte b() default 1; + short s() default 1; + int i() default 1; + long l() default 1L; + float f() default 1.0F; + double d() default 1.0D; + String str() default "str"; + Class clazz() default Object.class; +} diff --git a/src/test/resources/zip/data-java-eclipse-java-compiler-3.13.0.zip b/src/test/resources/zip/data-java-eclipse-java-compiler-3.13.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..a3ba4aa581421e1b324d611e9bac3425cfca61ee GIT binary patch literal 37354 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
KRnM$8Yoy$XIL`(2eIo2-6=H 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-eclipse-java-compiler-3.2.1.zip b/src/test/resources/zip/data-java-eclipse-java-compiler-3.2.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..b516f2ee273f3cf723a1ef049325ed7a3b9e678a GIT binary patch literal 27855 zcmagF1CS-*vMt=U?P=Sdwr$(CZQHhO+qN;?y}PGvdm3-?=;wRbXSQ2754%W>cT4FUO2gq6wv4+!pG zAY*$c(|<$GC;s=_A^%@U7gJ}Ke}lWl|93dve}Ws@+1a}ox>(xV{qL1%e=$%%|Fu%x zV+^|g?=K`^ARzMpVWpg*ttq{+jiIx%YJ8*JkN}d1d2DbaDxt)qB)Z_Rq-A9Sk}4WZ zpMf!bTJ3>c)BINl+FO8+%7`9tnBDQ!oYnKq_X*|zcNsMCP<1t|D!%HqRc()5kCAn* zxjt7l-&+alNXSVPw_2EO;j@0~oNo}(@6vLP!dX?6rZ8D=rian{VtG6t-Csts8Bc+= zU&m`6AW(?8B5XwL+fb7Tb+yjDG_eh=XxgFL_N3Lp4fOo*C6+;n9jqM?nE~R!zeCHr z11B0Mppsesi@JZ9fb_2kJZkz~oBlpN7$^`B#s6ReHA5TMf7&24X-jTP04eM{mWX^I z%{dTe>L)3lRpgdlfdC#d8jKSNrb8=}^r1y#Vy|EjOg+Q(@BQP4YwBGkO z2g}9gA|KD^C!_(cHajz1wBokYFU+_fqeF_siU^3q5{~F1h0ar^;v1*NSe6gC*AfJ6 zImKq$uTx@ahJDhzDye#8pxwp|FrzGCi}du-(tyONB6h4&R@o`~%8?4L%7F@MD$5l? z{=6T$4wed~_9uBf8=;LymvaZwFf}5haHye1wOaU9HT*&kMGfKN2VK z(|b^`*QZ%{CA^*von63f;1Z@2o97rM450Lt8mtG@eWV3<0t{nH3akbw$CMlb96^#_ z^MYW?pk$26!A(C18KXPVNHfT8Q6H#o8w21lB+VK^OyBF0vib%|)Ri!a;t;OV>W>Bg z1u5S%<$MLzr))>N61QbYe`mA4+?$+CmXp_${``J0#+W|{aDf0TTP|*vR612_#WsT3 z)#ekc)_rBjw16BcK6n(@`CoM1UGxZ#{&J3EBdRT_hEc;^e;^4p8n4(2NZZh7Rex2KVaV0;i> zLuV^Y1{#~G#YV2~U|tY055Qob7-h@z#i<3Jib@?kD3(itCreei^OMEeD7QztzWT{U z3{k(&B*$r?9KWKY8)+yl0yih=!fJ?H<}wM$oN%j39b<@#ox#vxOoWqG(G)6@DoB9cw71K8bKY@V{1XG1z?m-N1tJe`&>SpPIYw*m!5A#Hn8MZ zM)iuP0yq9K&S6J%JY%C2^MnYOj+uQYl!JGwDz+lPsfseDLn313j~#k|z*PO*y3}H+ zMyjw>|2xqW*|P%RaNg{#O|YVgxXm%`h?4VHCU{9-vEcw2`J)joJL=9Dq=h)7cwc|& zZ2s`VHui;Rl|kasA|3NM#-nKGqPh#whH4lT$18{5PZcyjhsQR>L zr?!Z8P-pmD!mF4+efkZUjsXvtl><#Z18uzd5awkEZ=Rdwv_Fr)(_$v3e z&BCDWJIK6QJ$fOr4!0 zvGqIMrsyt}i_|<0LzT~Eh}IrhuPkxCH1tS^xf=Esy%^yH!0p$kj~}-~8samGzj`As!E;m9%Ws4e_r@P&cmwI25&8*Z^*P^RaDL|BU&%Q2 zoB3Nzv|f%XmnILqAqV?7SGb&1Fqcj7jKqBdRCnkn`o=0g!+dXabCLNQsNVw_udtY} z?L1Z*9X2k6=5YH}OffxOEo;L8y!> zCwkOR#_uh(4NtuL&sAU}Ng++wdo^hW_5g`}Iq66mt)N^Fl1OhlvTG~o=fhai>-H4R z3bKt(j-(75s>KeuwwGAaGA${W3prnT|L?nhQ@8TJ>PAjD0Ve%7pb4Vn&G|OWe+h6Pe+ksKKTBwoXl+A)$i{50cDKx0uzNHZ&g-so2s_s z3qQfFD`V=eJMaJ_haJW}>nPLJswu8ZbBD>TVGS49v)Q&&_;d87i6$e<#WeFkf=5zkkXe%r8jOn_^z*U-%}z40+VEA@Om_C3>XjNkK7 zAsd#E#R!lZ0oo*i&W89^Gz}u|uRNV*>yFw`IK!ZU$Gc0Y`y6=jewy0msbs*o>MF)^MwoW(0=55i-Kcy<4H zB;P;NC-5s2=`BFwmE}<01kO0&IOB%cDB>6?)(}TAq$IlpTududg>je3%j!p^eBaHW zMdfcG@Zv{V132;EJ>7irhQ@HmpAX;^FN8NmFWhrHDf8C{+w%VW6+J>qkv)Ql{2Svs z!#pJ-yTo-P0M}pRN1js4bwWhs1IW~Tk!bIcbuvi^2Kd4F+w2a==|MQg5hY<~rqC;(4S~f){*yG+}KgIUh(JYt|z0*67m;vOO zx1pf366!s!Y9=MhjMDLThN|D38B6h7%MJ5b1yNLLnzpLu+AsI~Pm4 z|C3jyrd-KutKyCKpR^t6{UR=f8?%5l#oY+f_QWyJpf+}{!_JPD!N|WFMyID~Z`Fwq zVPO%CWsqSV!<1&{SRz|J)jNfiWxWfH9D5y7H#^5g{f0NL+4X*JKq+HJnd>~s**$yn z@jLlF-rxTYF+f?SLJ7j#Ib>w>6IJ>I#%pFty>`P!P+pHGkA-enXIYgK+-G|7$%HnW z71KDrEbXa5%0)|htV+P+x}U1-EjV*Kl#HZ$y^E70DT1E082*a-V~g;FLygXNG@AF6 z(7-OX2jAIgV`6j;9d0?R{q=!n8Rr?ML#@_i(8>4*2z3|uuN#yzQ6wT@HhXtd*)Khl zIz!&*o#^F7aQI#j;>yB!RjFZM`uc2acDOGJFs|&4? z)hr69*1IcwHxV|PCW#(_ObKFSSqsjYrzMamCL7G0u5zY(A4B0|_2GEU#FVhla>0%8z|twT zm{x-;oDY;=<{t`sW}Bqksva6%G{8058p{Z^tCQL>Y8pR2@%a2tFi)E<2-bj4;8{}_ z2plGV8NY;I`CXA`f%3hmy{UIw^LJme;XBO=YIZ?yfc#iLHP{5_7qSq?%8f8!81o<~ zTcqpcqOn%*ysQsCrPvH0b+@doIyZax;<|oO-4=mw4{1aRlj2l3Q6sabEST)-p4(BO z{U&fgpKb@8GkPn}y>z4pNxH8{q?^Hex`Vl-xDtF!sEWq|WsNX`BC(NWG|Osa!5X8A zVSOb%=Zl2+ftbY`B}7ubJXt5PbJo4X<*J&?b-ierBZsQvpCqU3;-zpcfY`h<9s$fF zQm%<3!(^32g6iTGB3J&k9?7liY$V@O=Tcq8`oK_5jpndp>%L<2)*hfn``xo_l5zoB zZs`Z{Dr;#1Y*J1rwN9{Gv zTT~v=C*cx&IxRAf;v0JES=2A_2y&nn*(dh+q+8@|`$)v2Ac*-4MgcjCe|m=^x8@;@ z1qaq#cVPiQ8v;Zb0A89@aQ4l!Uw=b*c|J>RP}slOdIN~&wp=0<9I8K_%9IfFXwt3n z0_87?%srgBfkb4H5pULBX)8!0o@tCJOLfkk|F#N{u zi9Wd_VD`vAdlMixY%o%h51Krw)9*7Q4|^-Ub^S?)dXNx#H(dM)Uhm+&LooV6krNfX zNYaY;TbuG8Id-?xrZ?5)aoXio8Y*qC*8nm8mzNvDR|V(y(jKkE`Y1PRpKWse!Y8#j zAL+PjoIO*~1jj!4XZ_MQ3A6vq&-~l#og}~CFtR%gdN0xHpAd(CYOSKwGgX=DHtpX+ ze2yr-f&ZmkQ-75!(c67V|L>+)7z7B2?msElU(s@QadI_wv3GJNRd#hSbyD$k_~+I* zR$*FdSOJN5xh%HQGMmq5E0j>9o00GpXjE2^GKE@XyZo$FHZpR18^$j!nz-W@^n=pT zE@df}7!!dd{HOWxcKm$1JJ7gA<^(bV%1^g)5)O$Hhg6BwE!lmQNzDS3%xmvvaiW{N zAED5}dorICyRjc0mjJkOVg)dkTvDan9Fz$Xv>}b$T<0AUG=^bL74;CGKeu@XF3E|M zMDb1Vuw<|yRk0vZT~(WmjYBg0F{1|0jEALPj3^;q{Lmk#fb_y^e+gmPp%jOW?~^-B zT1)TusHF566T&)STV?G$zNJklH-@;-OEJH!sFe|f!lx6IpjM4w-ngWb`PspR$qr_h zx)`F|EXUODiyFwBIhxBjCh^h(xMK&srb#a2+*EMC>R%*GzZE3agZCTawS)rv>^9lG%6BQaqBK`I#mqiIVvn05G z8Z5HTE9i&fey$}F_@XHJi`?AXb>`%s@eAAljB|20A>M@b*{$kh!h|C1NJc9+5dN4$ z3nXx69d7>~O!B0V*?!l#Q#}bXa+wg0z!*2JZZIdPv$hlOMJA%fjdRqb+&w9iM1i@W z$VfP-WDF$<)O+4}O!MMyY4Xl=VKH>?!2$ed-LpzQfQ%T2o`lB5XZ}aTD!h4h{qby- zr)W^+!POP25`1}eAF`Qhj3}%$7b5-O`FmeN zZXs?MF{>hp%6H6YpbBHn{Q%fE#P#a$PN{&E(A%uvb@0J7gx3AH$v$CEBe{W8dgU$6 zGjlN3)f3LZ{RF$=a?$7BsEQ)b&92pJYtnraiB?IX-22u za96aHr#-r!V?nuJg7i*22Dy{CG5`}N;bm*%UCdsjW!2I3`e8NJ(kN43QZ~=f2UEWP z%Mo{dM(Gj$(%bg;L-Ie-`_FVytja+QIyC5xs^25`)t@40|5?T;0eUa^2 z3CW<#j@_HTC-u06d@UYHR~b=$W_&oF?Hj-J^Y!-u=@`k2CNR{`4xKn5UKN9`rluj* zRa;xBTrG3@jWpKjlUS5+B*a77DMe@Kk(-*?OY|r|Zw5xOCT0=cr zDLf>3GIwCvduUTH4LJE+rFVl8-wCe9E+@hZ@&}qFQh0C@OHZ|6W90N7|AmXm`x-Oc zc4m~zq@im7u=t$C5XWK(*OA@W4GOnC*7f+eeNk>|wVWPO)jTCQ5D@s^;x55|GN*{W zx`n09{}Hk@aT`=Yw6Jeil$&2zjL>Y-&^sYUUeXnX*qHz_()|rsT24R%K!KDLi4cJ` z5DaBUjL`8nh!7#?06YXbKY|8 z8%mYY0lRdC9TT$_mMWB}LU2I{K$5q-_S(jNc_y~9t%kgi-Lgb^bCyaO)7ZV~*RR?W zvK5N&vRzW59LJg1V{eY34!kLCEpIU2#rPaCipD=bvt3F0 z)>fR?Af{K8u4G{#BodSi;ex1(^@MhA^kP`Bgh?mxji|GYYc!V1O&z^3CDGuFYuLeu zH%m=p4$r9VF1Vf30CjY{8Eag$I}?lICme(IgJ_>_tOWfh5HzWPZtB(FWioEdg$6w# zSv{%Dbl|9-w~fT<#<-6@!gVa!_C$^uG z8YXaentc}Om@S@@(TUL)N821~A~l9olmpjI-yrx>uQtfcmo{w*GgGRlPi~LxlsOJe zs{WXM^w2d=TZSlJmT{)VBfdT-ZNwiQ3=#ZzDjDT6qj5$vXK1Xq^np9#iv=382{uYn zLu^AH5A>CPM)4|a?|x(L62S# zMtMR54yG#Vdo!eJhJ$qSO`zM_3vn~CwMG+TiE0=#pe;3SLHDXnXA=57)p1{`)k)10 z4izDWX#?_S470R;C{HB2+*R@Y!KHu`HYWmJ1bc8%V)rb(1B=N!o^*vgeHB5OZon@k zJ*>)%0hxkylJDD`0T+F-@EO2_hChAhv0?>2iT3gh*+)$%nHtUitHj| z$lFV09+pWnmsfTEAyGUc_VPe0%0D0WrXVkKAGB`SI)md#UenoUGX%=YEc67+n|}%g z(~a4*xGS7JnYPs|&^(XHNlAI>;gQW7S*dHhmH%PHjnR z@U>dQ-&%w5!pC%JezCQ7Q)s>Ic)@9^Bup>lhB9w(QWT#LH357 zDAZPu(4IzHeCQNvMN&s`C7x?FZmYkobF{=c54o#|$w^xpLAqTEpDLP_;;b9Dcx?#g!s{-mdlrObvSG7&l?Mu^?LfjjRS333CzuLhM8Kax}Wyi|u2|!$5wsH$M%z@y9N7G=mXE+a8eHUP1kU)-+;Qt90Nhr7*-JjN`^V|Ep-Ae#0FsyWip%!>`xS zCGCAoDf<*|NUuQG@mfj5dT!~GvbUyA!bNWSjA#}N%BvA4hdy z6UO+>mFu^ueQyPFxZC1>AX>l)*~mLRqnXP;7;z7$ztTc9{)ln@sCUR~KL+0wT|ZrE zcW7A+3B|25D(<9k) z9opU_s(a9)y*;OV7ch4P)s2l3EarIwz&8f1o0v-Yn}K}Z4S{Q zoK5W1ILK#6E#bgh3+tOaM_R+%(Yc(7thhorfy1<)zCF`yh zr>;4KAp#A7YUKis3t}}^3Vy0!qLAzO;LzH@!Nn7C&UR!+K?>J?8PEboK?@rgIB^h0 z%8PC#h2LXRGZVXT>^o1{&le{U+so$Mm(|WkVFE#dlIs;jjgyUe#>EKiafySC1?wE;jtS!ddNr1&&*Ij@BoL4UcGks<0SbLI+Kr&e0ZfIo)6TKi zEKx`thnUl2)2nm05d^V!UU4E|+3m5m2 zAB`9kzM%w*r!G>oPw|B|@f~N1@6`3TM7sHhl-jRBybuMyCq_ha31Xer3Cip5uArZG z;+jwfmis1DTr_q`eNF@ZU^)-GfCkn9*%FVvu;{QoYB`#BoN)BZ#6??dOhj4-V$qUf z*4Y_@T#M$gpiigYjN0H{!!syEmVc0C<+eM8MR}G(5L zy0Jg47&LWmnKTa=J!qzxGj-4cUn|j0p-}20m|eldgOeiyr0yG%XGbMjrP5^7g!+{Svq@YrX*>kpB64^lvP&*?$&EroGeGM#N=9(@YR46A za)VTfT2(1EJV)>>*rhE|$rW0=e$m6qcDw|aXwyWTe3}i|2HtHo^k^eF@xs`&rf||Y zTe7)eO2rzJx6B89sqEPT0e~C$YEBTUN^)Tukpw#((HH2*R#-^KHBvTYU3uh}*Q1VO3kJRyw`Hc%*Dp)OY?$ zrWx0rTwMwl=r!k%(~tLqiDpJZ;vnH>L%w2#4yI;wI^3#lo03JIjc&yhwXN|(!x(hq zC8f!S&5NT+SSUrbbxx%6fhRl04McY3J#Qo*L|y(}_Q{vGi=%FhhM#bK;tT#juZSRT zlpgs&$;On9G3M(I|x>RrC#3psY+QAo|@{Q4!YEN^fPxIEna)B^E<)-N_CVPkj z`=;g454wGml->u~J5STW)^xd2l8TSum7KC=ACyLZ6s6>+y3aZK5Ix|j*r-qKif*#Q zY?s#LB^zP{OH}QflX!|g>eqOvpVKK@lkgZWbI_dh7}{T_CsS?BANZ+0_|67yyjE^; zn!u>fYS@Dj^Eoc}JtU2HR_s!e4{~N+k;$)~&_kYtyJlA)hdMc!xQ)|hEJj1NmP@YI zNo?6*#n@e=KQvKq_~i;-qci1HHcfrpq$XJbb$oL7$uFuVKW%_u*$@27K2f9})xveG zTPbTgMJ;Bu<{zB@Qp;Yuu-|+KhYVLe$TXWqH z!}~j=x1Dbjz-4)3*i6k~qGDRE6w7c@#cB_Ffv?i;uIRd}Ol^1E9+J(|w4Y{D-I25S zomF(&qk* z!B2*>?Gvf%*^jB?fNsR?JK!m+im=(z&YCnUO?);3ALwj(nhlUp|M0_IqBr-FyIr%p z_yxJ-@BB&nJ}?NCFH@*JA2(oORfffqx5^KD#lseWoHw9K>QCt^i;ALUy8QoZ7{cG+L`URz;?&lnfjFq*r)x*78dNAIhnQxaN-LoYlyn4>tRd6J_5yhMHyjn6~ZV6y%(=*{oxSZ@$4c}Jo% znY3r7m_;>-nK~%okt<{TaquERP9a0iab&WOCNpqSWugDfo9V%iSVn=&ohzF&QCyl*l2b*$DRMolU%QOfe>&*RAur~G>2a#=ElEt z4plqo%fcPyyO)uqw1q7B5-A*^*yAasNmpmej!rr;oqX0HQ8pYQsa-h@QSgU_y`Vo6 z-9dsH4Oan?y#T`+v`M5z19zcyW^%g(u9Twi5skev9J#Z+K{7XNN<2ZM-0&0*;47oZ zMcPJ{w1vk1tWkRy#zx9cYm7fVF~?EUb7*%&1%8R#S;TdO-OqdXK8R>Kt7>ajYthG= z>%npLIyhI9!WRg7shKr9SNh@h6rcfyJM|r0`9tGvqtIrw=Ld6GrTYVR#YMVoA7&} zt6}2*Z8TrP|38||l4hbd&i|~bq^3p7qp4$!&fjj}r>)c1gG0D3Y7y|MA-ATgBP%NE z-B%SwB23f5(RQ1-CuHy?u@C+#vrHZ-q$&i*0u_XVNAg&CBr!x)lF4}2KITnor`;PHa zg&$veRq-$|5{t${;i>h~;rK;nvd$4BIdLW>W5s7eQV-O5D?xd^dZ6_^v>lR$r$}Lx z6_NxH5s8hhl+@kc8pJc!l9#MF-x25w1@U@xBKV-ZBW{2&ebt&;IEGP(VxE(tO{nTw z$6G`FJy=4(5f)ogHrF~)k&uwhyi)R8n5?R|B1xfZZU%(1B5^Mlvrr@FV)do#5iYD; z3uny4=44^N#mXh*JS4CyArEF0)2I;vo2bd+P7*qFI1DHAO8LaLI@GI0I(9UU0)66pw!v*<5*n>J}%J zfP5`~s1I*tF2`Pul>A*r0YJTy8li9%mLKumE=>bzDUuZ;Y)X)^ax@mnUw(hokde=P zH8*j1s%c}#&b6`LbaPyE!``vcGR-k+$yJ;(X>H5Y#Km$#GkJ8%qArw(cYDrv*k5VZ zsmtV^=tQOEv9`GSKmoXoQRqG>GmE_ngsfWdI*ep39cDFiu``l}t<`B-#%2m%C#JAG zHdSl@PA6QL8z~1lax^5wT9Ugc(|xRmpQDQe=rVXC@_|Sl2Rxqc>1Wi8vbX+rx_@j= z2F0t#V?Pq-uY*{FYzei^n`9bq5fpZmd@u#Y&L=XwZ*5>+A+#AS+Bh%5(1Sdi zpk+j-I<{LQIYinti(1W^moP)Pb6GKI*BXk}nyedN_Jt~Sv!%Y+6zPZ^!4T{c3RQ^l zqNO_xYaJm4|G_)*)b0cvHCv3H_)2?xcMYxTfNseBMgq5@>V@U@(7RALL8*6-JRzhx zHGK>y_8V5?@9OhJAgvyE{N+Ya7x6dMNtV~ zuu(3RNF~G2EmX1_u0J%P4H(WgIe-Vj3+6lmZYhMxP2seIQP-gPHB{uD(p;JXC&G2;SiwhUb-j*UJ(3;s3{x091i#qKPjY9PT%7 zj1jbPorsP*isMcy6n0*g($}k}|JY`ns5f`caG}RCrP3kmJzD=bAhkIgFAi4cl^AiH zOzqrM?GPPPA{caO55(}DMpX9kCz85;*hGO)A`8?9e*_c}tB?qEA*#`FD$=v&l{*$+ z6LuDdgvcUHu&)XPd*#Z{ebNY)dFAX80=s1*9akbYZi!iXQi3$8e2JN#kmv8y3fL-< zBPq7n=QxD`qLuCtuY83cNaw@qLXORD&}Bs7XN9w@r;MKLQYyIe@{ zNBDq4-{z4E@xxw0Kz!vFG}kTF{Fr&o_q^_QFv3eg^j2_=R6g;9IQ~5(`&)(Z+`3$0 zQg$FM&n3nr9m*uS*b*g$huEI>+1!>^S3lvGEWtK|r$hh#U2iP%wxeM@*G4hD4TDqg zC~z~(82f=7>~+iD+}?mcHJivaYZQ7v`X=#ciYAKH}`4VJO$a|v>7){ zaX%OX#eLX54xLyoIx=T+WDdAef(P?Df(|*k=#=2X8RjgHvSGv|HmOFWp_&# zV~c;(l48{?Wpq@rc;i7HunN$$3R38omqKf2fNTp(=`0Id77AMg2Gi&fhG}@P%p8sl zx3Fp*rCS|iTgh>%Ew`<78p>R2af%%ynZ~e;W5y~X$!&|iWn)eN?k7w#gpXwI*Y4{# zIX6BpfVca8_j-_u!2(z+92k;C!JFFv4y;HVz3B)|K;1zZI-V1e>Tu8Rfm&dDN+g0u zw?{-=L22Q4GZq^yZMGRIx{JkxUuf8j+Zn+zv?WBk!g0HBxZY#pe_}1%3;0beCLY9t z0u|&5t)kk_Wm>~#GQx0azeKNLurnfcb(To=lTO4m*< z*OA%Xau{pZ8eBHfBCzRKtTb3BE1h|4GK+K2S;uHuP}Umrh;HIV#CBv-xrpdNl~P)A zW0fyY5}d|9fVYw%+80(KPRsnVn;XDo3byw=Sgk^8?cQxUgo#+lldI_9pVNztxgTav zB1L%N?3%-3a18Bt_BShvLxo$5I_1Xc!;E_4*wt`dUNu+GHioP63}MAYFmf9{FE+#} zR#n-!x+dzosi3v2F!WRC+cp|g5Yih{s{5Xd07`S-$lybd z5-iFYG!{`_WEaq#Dgzp^a9?J^<uLf>Zp+Z!V~HO=@*_dkp*CUHA1||Yz?a+QkP@D zz*hVqTlt||rHkm@75J+aI4BC~+Xba7VM4zr73SkX^Wbaa``K;{@O$gU!OyWSVnupF zBihLeY~2>v5vs_=tn{ShDj@> z#WgcH=w)L6Gg+2i=@bz3Xvl(4h%7#FLHQGWVt7ChPugJlq~R=ks!XY|(rrU$D8~}< zx+}BU!ZK&XyW(d;`!x)^50<)_5jg}ob_`>oSS0C8Lkv@)UEu-~wTWW#!OG!CES_FG zx4L;XfXG2{axqDyfH*RMLe9WQDY!<{aaU}+9rcCky+2ufOc!ov2X3xc7n2S{`58B9K8XcH)W>3%ufNluIR*3gJoyJ#PiSoi zXJ7-e2zzBF16>m-vUe|n4}_{gTt6T`*l{ol?p7>uIhGf{TvBd9kz6!OK}^$a9G zGRx12J|3vT9k3lA;$n@1J=~zM`9;6$jbZBy3VT4x?}73JS3}qDdZITdz2TXDM4P2+ z`w?s5J9@UVNC7V5dg_>vE1IRWn9>;PvOB6qErs_9Dpib&&?dt%HK>j+Q(fkvo0S)@ z(sW&IuW zF8Qg-``hB1xB>rQdCX@-!p=n$4xZ-Hx{>HfV#tg4f_{p3G63_-HkWSXpQqCk) zvCftSC8ViEqqHWKjk?Wp*($w!D(Ax0)K%{b>wJfynC}8rV$@0rIFYG9(IQ7i%u2gg<^QFJPpVv(qWu>e|kR; z(#u}Okm3@qQJ}Ia{aI^vYc74ta)WCP*BhEHB$M!5We2FI{Z$GF84g3&gxzeGlFqOa zyHuo?jg^NGL{vpQX4w_v)NNK%wc4`Ejvn@yw}!=KE>ruu$W}`|fL?;7WJoYNg7c{2SkOd4pwfdqfmHopBV2k!JRa zG)$)>r@KUg6c;-~FH5h<-0(-4qv~MyRiRgh*?BcJOov!_mr^+kV8_8o<(^|QSklkM z)|EH_x5eO6IBMTJL(!pH^YZFKW#%4=N|l~E6|^AB^Z?jL0KX92occ*ivESy_7`b&B z|6nYk^uv3QUy;$TRH1r7InPVXcYHz_jNM{SFhQ#yi5g0=njJ%7SCTgr+)(9g86*X%128cr@$G=PS7Tmqr#fvl-ok#s_y zBlcyuS=gu^q>NBfA8_*>&U)%0l_icL+abE#D94BqMcuXpz8aWRz%EHil_j~MFoZ&8 zBYXz26?iUEI0?#W;mFg%*`_j}eJX~n$h87E_pFE0OU@InyI+lbw&}$E~^?VqsmQ!$UeB#V9h|4(m zJW+vnZa=aMa~^3Z&SG@yEDL<3k(d>~&_fi@kxN=5xn&=(lV83$nZ2Y#B#OHk({U2e zFayBEke`}cp4!8pgH6yI8gvTPD6>4Kew|GoXo)2w(^Qg63xS=EF!8i$G|8s5TODEP zARa>@A%7fGyD-1pu33znRM?L_bTLTIVHVO8=l+8ggvX30OSbH`veq-?3_K?XFP1qZQxle4k#Oda0-YQ4!2+HrpMvh&)wJt zLQf2U*#zDNy;;6D#0bju=$xJS!1A{RGEb*LHmcKnT~>J&D7i8$}yc9*W z@VuQ+d*jedvzI3yPC%+XT-bS#d-?P6?%7S@|M@VU50utGGce9rhbzA1s7ZYmMywfS zDG3=>I5~C(h%}l=vx9e1l7x80HX@k-n2tQr4p>eH3Xab?kwf}w>tH_{U0HL_@&UOg(zPne%1%wbMj1D+$wn#7=%h6|SN}77pLy6K zTwR-)4UU7mXYR(X=0Z!eRVBBIdDCzWpgdo4+o#7OHI+71FWYkjHRF822>grwl>ua| zo~RXsS8|2rJhYDHy~n7o0Wlo$nm`ooSDjuWXa=eB5ue)#4sbI8z;| z*w_`Um;;7~U63hn#hxOTSilyG_*M7f#C-%qf<1{7#K#3ynUu+viz?PDu1#^;O6z!ou3%XSfCni|9&mNph>}z>W6kybNy#%GMLxJ;JI>F{Pgg zuizEtnrlga(7b-us|LzkpGZ^Op4>ZZ)%^6R-s!PwC!91DJ%cojYAJ_&72AaI!f>if zMw6!{^VI@g89^E8D}zws6&~}<8uF}&>qNq2?)DV>J)80gVs$K4g``CpDO>_$eBzK5 zW8#(!ht7MVN7X7xlAsC5#}c9KD9HCFptj9}&F8l&M}Rx@Ey1Q+{+<)qO9HVq!GJ2J z!z#GW6HpjZ1hiq?Yg+VcY;ecE;AN$Aj>8MWF|(oE%=Xam)*9-T$0tjsCDEjcTsi1F5RLnl3w>nyZlpxt^$%jNqk#8g02GagXU4b4x>NDINPu`HRHMr#(T|7M5wh1wqKR&>P0WrXyq3pN!RR{= z4mb43CYdZ4-7pd^cWQ#)8^T%ck`MHjUroBgLqP2pwwTW+ZW|{On++!sY=-^;8+10Q z2ChlGL>j>cbV0SQz%+!Mq+pl(7?=CHS0>07e~P5}MFpPaJ6|JA@I*-l38NqXL(z zPzmJN?g}K@n5|}mJQ`Z2AWTC^Ol{URj@-HD}_UvuCMK}hr=EV&zwwi-5E)!UI!4uee zHCu=P2{jXmHc8jFxIC1ZlyWT6MLO!~i+3hK-eiMC&d5VMd{3`G&^@QzTRFLmeB1UX zXF@H3`$JFPKy+Zo#j$sHr$lYqky!nCvzKqQMF&NklS!%3p&g9Jujuvy)=LN$=5P&e zF0KepQO9ZrKMZGySd`_6dpNRD?HQdN&B?{%>YQ;p5wxapM7#|!FqA-z0ygHi-r%X{ zZ!VBH@uwSNtz*_P^SA>Yx7RQjnp4Ih7divTh#}sg6n!Tbc%F-b+z4f-qBmMEwXk}2 zORr6(J#_a#k7GHGO2y55;0lqG5uU{+gFs2>P=dnDC@nx1yD64ylCotZ(730MjU`&` zmtcSF%exM6Whyl1bYy1*nuO)~{U6>w0p42G3tQ_4H|iHXG{{f=B>V@k5io9y1j**| z(VbO{24iH=BO|)5ZMPMNwDENtVcn3*^Y!;Fj`L$VCRH;^>CRPViZp3s3J+fh&wxa9 z&;{}(d6HOD7upxFt`ENI$Re(HI=0EU2QXIo4T|b@SFkSOi(iddLyER4wkGY7oX!HI zN5QTtaBED8XMVp8c9QWZ1%?cIldmikyT?{bxX(6#!|5JHkuPsyIDgJwJa~RA@n3dm z5Nabb)CI5>(lmMJ4m3186?1J>mLo+((03(f`=iOT-pA{NBR1^7ses2{sQ!C>w>VzW1oP)Kcd2Wd7`GAb+>X(_G0XJ+L;e z<_U&8m14%Iv2=6KLA`CeQ=!+PEH(+p_u~$FoG0hLHeR$D2c@NyRw@xzdn}f@6gRZ+ zj7SFkFxZnkbM2O@{nEvP|}q3n`0)WM4lN`=tm(ydMe= zeM$%P@e4Ctq3omV*%jY5PqsC%=Z zlpoz8^`g)5IrE6;oOfoexz=8@*8c36J%4=HzOT#Es%axvX3nj?sm(rjlaLkRD_G^~ zBp2skjau5()9sKSK)|QQsm9g6s`N~x2xG{N<;ZtNPN~xUN9Bxw-!7PrlXw<(?*}&_ zmB;*%fcoV4eP{5?u{7qA*(1E@GLIXCXlqW?Lv~_3mJ2b`#KpNOy{UZ^FTbGeGo$^6 z5pnEHGN+Z1{$YE!aZaZBmK)_kT@t0t%UuYNDWNQrGe3V7;v^IIq7vwq zesxt8XSx>y4fTu)ik8xniYoa@D;52|HaP}*DCcJ> z{fYn-c@|Sg2Jd*P!6RaInO&TSmh2`vtO4_A7Fi-WmP?xmwzwP`tlpFmSIJ9sMmKTl zQ-o9#D8)z^-qqN&c(KGA;&=x1=TD;+C5~E&$8E5V zVWJbz!70z|7Io@5i`Y1LI=W_c1WeQ1`|a!NigfS7J$)##mGue{5%pwk5XyE2dR4u0 zPGLm%Cc{={O@b1EL8c)xGZiU|y6FT4XsG{CpeCJ&!-knT^kF7nA@aP<`tn(>BPsgD z$X6z-Lnfqej3{evD8S=#8sNl^a=Wor)Ik;I@)&P@jfzaofDiv$n3<%HVHJ%v-=F#1 zpT*cNFx!EoYmCZkg%MKV7p_y-T%$p=6Oo$=ah0%xJ3YggaRhOm8cj;to30Lw^_h;V znFW_i;IAZLca*+e+J-Cv8#=1P_fmDyYo3$Bj%yVQk#>9`DRa=u4btsh}EQ)-}u4m7+m`z z5*s8kSfmzm{-NWS>=!FQ)NolA&Y_zA&Jbq9{igigs~`sHT4%ZbWNvv0!(tdoJ4vq( z1Ib)&<(3j6Kp}Y>wz7LUIn~MP`?+pTDwjZ({Jr&zfc63BvM!EKgX-S_*dp5c=lXYd z$eci>-VQzfB0YYvnB3}<&Fzb)Esgxd;u^6)norpB!BqnV_j76Cb){Yxwi@>-Z5?4l zLX(Gr$bP{dULiz>a2NMPbv;PAlaAv6M?({Up$WS9qSMR#5?|4wvoO}gf^{2A zsy+b@&266CEsCtaa^14im&T&Ilr;~Z!j!yE3(f9D!2qJC!C{9 z%P>$v!=GXS6Wd29{i9ghl=#dsJ)Yt47maImI`m*fb+2^1TIrA-b-9nPqP zS+nE_J1D_%AAMGuGO1Zs1B_`NncokP@5dS9(vJg_(PLTzTBQ>s5uE`;eCYj~caaeU z)+P?|DpFf5BWfbfRhM4Nd6F;ns}3gN=T^oMJ|SGIRLP;bgFdRHWyl$paNYMykt%32 zEHEL`#CI?$DOZ^D2NTG!puPpTB(nBW=&q~7QYENfN}J&-e6otc0kZ4Id~#ENrC)&g zGLq7u7LG}ZVO!v3JwZH*UPA=ZVWdlR?>x&>#c<)JTzWPX`N-&)MN72BahvE{8g6gw zNJ)zNPa{z|BpNx)Gu!j>$!9v#lG_70*hE}3af68@_Pb5ID&}As!TtSfPRpp_H;T$e zwm5{m(xVZ3>c|)WD9TvPzvUJ#aH!(xJ42s7xyQD{tRy@NsUC?tAgN$l_Yi2tKV#2V z?UUMU%qU+}YH2X3Weg1R3~dbU8PnW{T zfdQo>zfFI*lB3L)1DnQ=5@yCq8&S)l{$)aNhdph>Y&^cAgJqjgE@i{fJG?j%NcCu7$I)zX{l0~c)mOJy# zobhmtbVYHi@%RAG$L8rN=Eg|g>YR;Xy93K+)l2ZGG-zIXW^jobov>w);+(7O#c0kN z?sfXehwmd9-NH))2E>(ow!XvjzWJHyHq)sYZSFF|;T_>NW+D35&ZV@TT!mpf2U=}g zYsRsS;)uq`&1)q7$9L}=r)GOI0Kx)oiJh@Y7IYMEaOWb8jP+O0wq=%F-+x5KUR4G{Uf%jp##o zU&(#&Q8)E;dQistgJ}V-d#HeRW+JE9M`x7crdU%uzT(-Q9uIuYxP`<)kCLX4vc4Q8 z;q$|9ZJ&d^%-4k-3Drj?mo7jQ=>_AjtZBosQ_d8=Vs?)#c8h(*l**-k(bF;9)&4^9 z*iw_6hcHrI!<|UO{e&_V!~x$1ml0)bw&?NMst5P%Qu`HBdT2&(lR`1x4lweC@g~^V z#zM6I7^>bS#-KUgpgGUL`<1~z`8w!oOc)wWp!7H)DM2zYVFi99NS)HF334(+sHwnf3!% zgS24ZPwcEym0jFip2t|Sysm%KIq73_U85*VE8b~erXC}&p|IilyT0I~p*%X-&6U+O ztr@OGWF@jswOTW-T2r-J<0k~H#&4pG*F^#&uWu|IKxygCZQXl^Fpb^O>D}k36ECZU z6kDTeKiLA@wG6+gBe(dRX1s(GAzXjcs-j_0ijx$aU{i@vCga4kV%8_Qt zwZzoDlWWNosxXhaT}y*aOXp zbe{uPQG^)oOq^?h0KOI&fqw={wNz4H>1}9CeD+F5?&;YbGrwO>=wEisK-n(T>}EyU zg2g_CK0jQXWM!!uKBmVm9I3OO=!wb`uU4{lWIw*xW8@)a5Pf?iN4v-z=m*z$3ZF>d z;>eR5oJ@G;LMdt-Av!VrVthKVAm_dtXUBH_l4$!Rw33AIu&vM#H+%pK`oPn8 za~A04Ojux@RE&jwC0dsoi+6&gHiF@flU$XjSv+*Zct1fl%_w>PI>nWj&T&E}F$hi* zxUHDK~yX^o;Z3cR+m)Y9d-ddA#MOIh+V=`UE zvEq@ufMNq^T5Fp0!W6T1-mjEBFq+{{7-IqXZv)bl{lye%iu?Qywm9ojv5-rug*Wlr znn>4jmV%Ua1Y2}e&Xg%D2DFxOscke9iQDiG4PK8#Ph#`8Qz!B9+_kzHASp=+n4VJlQQ=(_$&CrF_MU*_q zifGl$6sg5>Q>j=zE~t|_V`V!mddH~D*5liHmG9QxAX)H8U7GSX$kMd+Dr$o15cY&> zjAFg^{ATM=N@4i4$N2kUS;A7U!u@Xe&0T)vcQG(kT*4cvrI_|z5UAF~1-!V`S{ye( z>{M(vv<`_zdJ_vZJ+A5hMN*Kn9vvmUqMumPz$AB30|p~&#WKxL)>0t918WGQq%1x( z6R35fKBvX68S6+<)*s(JC!L)YQJdAon(xnA?9VFM?jay!t;_!HxpkL-X{RG8_IF^( zR}TVyln%0y%iPItYr~QY5`Kn}@q8G2KC25detekAvEatrx@B|f_CnhBcLk!^oaB64 z4J1JCTGZu>@Pf`C_A=K<(0fJVj$xYD4BQm)FU z7Z#*XdzD#pOX1;O1DiKHY89N-H3f7EspLEq20ko zsiMt|HgfG~GH}Un0?a*z!WtLe4?Ql;NTsaYkwE$t}Mdf1w${8v~J`;+(XbV~Z*5?R3 zaMNNaV}`qX%g$0^A%lE zm7qz@HvqCMFpa;0UusX>u-sqcqbjP>PFWbQocA4n=fHI4dW*)e`1xF9zyG3IWB~6w zq6D(6ULKfUW-4ggI$K1+CO3ksWc^e=-sUSj(aA-KR4aFqeT6sNEaX&DzUkHKHF-SQD|ruPrxg))ufP^Yo<+uWYI5dXbi_ zbUWZg`z%JtU3S%;sr6Zrr7_Yw}uZ_-%feRo08B}YFZjce+uF6?bBZg%r zJWVdHYTpI0s}EML%U52inhQctZK+0pjcAV7+Ms|d&Lv$Ci??5wJ;3tWDJ)Ivdw9|> zT!lnr&SGFLEWGbrH-IxsJG_-Z_m92m_yTW!)&_Jcf_{La!58{v;6*m6#m=ie{}cwj z&ijB|)quE8$k9q7Mi9#il5z5oz9KNGOFpM|#&ydgZ6v4K9G=g#B9D zn1JsBni`M;yMlOHS-C1abj&6O6qL#@=MPSsQ%>Tb_Kli^dfFGe+x=4g=LXyT;{30K z@Z<2S(wnpzngKCQw(vtzoizepS5J+Qt=mLIDrWjj{!w3lB9fp4^|o?p&_macz^&k% zyu?Yp4|MAA4#UBt!MFIl3&T%e*UJL5Gjny?azlRzXg9+Jc%ul$belPvzEy8pGMu%* zrELupjO|8uTwyId2`2jAuT)$|tUGZo8sHd0rzE-b#}mI$2CpquV3fcJ)hr z2oR^6)HJG1H{~^MFcjXP6+;-H8jKl15d`%hFw`ZO3pdLxE740eW*c8yFK+La{SR7R zcAS1+Yl$e0WKHhxF69RtI1=yLqJCOc07?+5a95Hb%Hl@a#R!FTO$Ns%n$&ev*LtcU z(GUovh83=WgJLS~G96?Z8uap3DVYRZ2UO5y_Qm+i-KhCa8IO3nzD9J@i(;ZYp<3$l zN^h)JF*G9=8nV(c8J#vH*gysGp-SU&fAS0TRc=hS)CiKgn(X{21Hu^$f6iD$DfTJJ zgc&(v#i`<`)QdlJO97nnEgX=cKrjcw>GJB9E?!S5jZqgrSE|@3bdj0BJcyF2&J{JO zNfYx7R8($MO8FKAHk0JsgPl~Ui^oD)>&O|8sgz=`yX*g!P@+q^@@yI`yW$k+OFsF* zOhD8DZBQ$^K)1vPmm+eLgHdtRI46d-o9MNq3I>B@q!V+L0EZX9uQ28oU6do ztK5Ul5_)_p+#8`3U2T>eooS5}n7gs4uGlQP$jQ>9Rx9OoN|W(bFA-Jt$Ll5~1TMy5 z^K24i+G_-C#g{FmDXE8whOF<4Brz4c@+ns8;qOU>uxF!F0PW!N=g(s1S7xM?NX)gi zM%$kRRE2(DThRjHAKJENB(ha`2AZ|!h^i~OBHbf>Z!QhWj*uI#HIS!Xb80oLo1dxw zR3*h-)?WwT>*GtfVME1)skGCT!lAz7VKYisW@6D6XU$21AbT<327_GTgN^K#8(i?B z#26Qrb2w36++M9D0Cz{*09e~JwNaH77sa$Uo}jeDVH@Niy9cIKP>n{T8!Ij(8qO$a zZUxfJUU%DcrbM)lOnol&-wZOf!{JC;%47S%wZ3rM*EmyGh}yf>rS7%w#Z8PwGoMG$ z`4#2Uq4{fmUOj@AEYa_Yvj!EM713Kyk?15~g+xYIkGy$RvFwGYHnPHX8FzvQ{)WGD-aBVJZI7&ruB;J!mR9FoZ`H~>&oHAx3HJ~k@o9<0^ zP?9=nbA48Fy1lsm8K(DfbmMph!{EvkvQ`_Axt`;U%5g*{nav(gG0oJuTZ6N?x)p@1 zmb&r`gdEmv<}N>#T{_$)T4?jd-h3cYZ8`0H60@?$uF|%Hp?tkzvm3x>3#YtqVEkc? zpLC|=OP`^$E;?SPOo)sog${$bEkLG~fI;>hb{@7~233URI{<3Itrn%aZPAtairpBn zzB08`ytg05rLZv)r*Mkd&M){Q+J<_APM&`-`kef*@Ktof-Vot&6IZ8C2ZBA<0yA(7&4)ej3bDELrjhex9Nl!2&UUEaQZ|?F?%v?3FthZ zBoh@veS#QBohmMKc84M@-Nn(u5?>9J!60xV7D z8<5*ST=dSswy&uPLhGo)EDwA`3I2c|-`sj}|HT-JP$F4?57 zT`-NH@0hv*@ml?PTK&S+G(HkvEQRiQ)XI-CN~+o#VDyr7U)M0> zzURRe&S$VuWExCL{-KkmS@3yaazm;3>yQR)jnH$)kj#Z~(zkw@uQHY82t6f+sY`h! zhm8&|m(;kzv>LE378RMcM3R$uB?q806rM{&J~8UsR?z!!F4Nrik@+NSHHEhSrTtXZ zP7^Q6$r0L*TU;LR4J7wBvRmGtcATw9`l8dum5hbe-TSp{P#klH@Y~YB%Xh0A3f&DD z_rx`cs>n8Q`KKrisyhaJ!$v!$xHBx@0x|bwzg5Z}0T$w>NPBD+u<8U8ZapcT^1zZy z(g>59UR$bE)xsgIr^HDECvs0QC?Z?sZcjP8ueC!*Z4nb^u%0@uLbpDl>#+Bs`wBGQ zXyKVjrF3Lk6;@{<6=U_}43umNpqblq)-R_?3mu21a$y};p)EeQ@MxOml2&O&>0@SC z?)}0RaeOcdb3sK{d9ZqZahT~t))@He4kPFg%Ug|2YMJ>57*5XyDmCE+)I6qm{WJ3Y zhFfuLAV9DYllP5EH-8`j%`{+mBjlzFi>YUlHz8C)urd$$1HaTC3Haj8f$i+q^-rCx{??aKx(T*2;6H%z3x>Rj6G) zXEtN4?8CVWw?#8`th1AVDu7KE1T5 zeVckxe(83DgVs+Clv)0WjM+dPS`CcKni&umMft|X8vJB_<`jk44wgHb+|$^8yOV+8 z%tKpMu7DN&h&-3`w{vz#+NMLJ2AF*BVLb9}2z1@fJkvrB7>VBpN@_2gbQB~dip;slS%rkA z9NH6|&oS=S_LM?dFbD?wF`LXg8oPH8$`USGCNh`inzFYRaby?BBD~Zu>yyp!YG&bR zn;!)0;$Xie84b2~+r-5?u}Lo7Jhb5|_jxvN8YqQ2e|b^Y_k4q#XHxJm8l&w z^{NKC)s>11g5NVa_W=|f*93h(C^%3fce?O{!1UDU;;Ur|{HT#gazbd>vRhWX3c~3# zpGWe=Ju2mG)KbdHytT^8r%z0&*WStbfYP=Us_9^$-Y>iln@M~2{)f>=f;{UN^0QCg zkoM%Z5j0<8+r=tY^RQBp4Jw@K)-oOXuBDWa0iKrh>5Z&l8<~9P;I%wdw((P(^z(j} z7k&o&5$1=$dxu72uAV`ypwYTykrw!>8Q61pyH`YI1ZT(|Tw;#-&AU3~;?1v?R1m5J zl{yuWWKa+HKObI?(>Z?n?EZXVlK+xlSslnw|7t)(5kTcI42M`BPe64p;WS zJN}gk^1t=|n*urP$H^g(!*>3o_g^_8kchXb4)_EQ6ZoxvLp)9!fkeFd8v-JG1d?W~ zQG)<@pdA=(m;GF}-}DNL+%n~9b1QPsvf`2L`_;D}=B>2mNq5C5+L`(%F%?vTJ@#pgX)|2A! zUu{U*W21OTTFrxL^y&5&TL1PxnwrvhTwQd$in;6aUx6c}VDQ$e;QXDhl^WV^i(>jRv7wCUD zZbI^S>?FPtAWlL5sgRR=>^Jvs-orlxE74zg|8}2)WEoCv^58#gF5sdN0fwUDgG zRu_;gvWM)TM+*vRd;y6&aNgGaiThI_agQsYA#t7$uFQ{ckoC}zxO2|J!JoL_`k(*o z|Ju371#pnK?_7VwJt~KTgenUiEc}H2sgQGgT+smujTZO|^sn_Dklb_is)JvX{Vz>9 zc>k*n$$fk=8nwtU$_uYAR%cZ f>&bcqn`*%gmIoFC9H6tps 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-harmony-jdk-r533500.zip b/src/test/resources/zip/data-java-harmony-jdk-r533500.zip new file mode 100644 index 0000000000000000000000000000000000000000..f6c89a135c17760c4e6e1635cd0ceaf7e48eb3c9 GIT binary patch literal 19114 zcmafa1CS=cnr+*hwr$(C?SI;swr$(CZDZQDZJX2fo87(p?(U1bZ!5AYE22(hR^*8~ z-^uzi6=gudV1WMZAadQ4{`Z@IT)_U;whm?tivJg}8uR_%5Rm^sSQ!6*Kyd#A8QD6R z{1@b6{C{r_`Ts#WnK(NAI~?`z11O-3xNm6&&e_qTzb_UE4FrVyui!!s4hHV@Mpg!n zj?rp5wkQ&)U#1MYBeY|2G)Q>>7*2T{kv3FpLcz90ea-O_rU{TC`xXP05r~oe-r7^0 zV(H|!IV{?=zKLMYYFFdz&Jc1xQ~<)9&n>EEblNmy@2{9x%qB zcLX^9Z3}B|9+qS}HA|%y{HdkJ6N~1370497EGm9_(}|&Rr{&D7aA{{qXn&h7Y>h@A z)yT-B7cKh+Txe4Hq2x9n@m^U(Stw1TrE*GeluQ7pB#hJHfwYsij|+1}G>41Rab>Zg zdx2);l9%~hg+SN|Sj%zd2pjRPyjZbAy?WKi(s)*&ya(JsR-layLh}-heki=-1&-Fs zqc$Mjr7l}5$iRn>XJ|eP{qC)4{3A!L?4J7ixxQbp2QP=Fi2sS2ojOD&i{y-{Khs^>j>8+>ileC|F0vEPaT*Xs>%&$~am` z+%&u_Cuhq?yNk=66qQF=41M@B*x(*&%zjZv!Sfm0=glSrxiS*x(LSqN>(x2AIw=CI zl}s&PESjk(7k?!}6;Rq1)caTNtQMSn1Fvmo zd7}F(R*0n`sCn!~pI+f9cwWIVZa1~>fML*(OJhP`(fRwFrkUn5oZwRH72aufnt7VbVe zFI7^q{(#7c8y`{V#>Fk@?v6t0#wFEbj0R;9asN>QtwmuIe?KVynzl+NK;kk%F^K<~v`Ulf9^982d=rn~6f%`hz?d}K8gIZa z0eUYXd~ye#b&J86z|>wMUc!c*cG076^K?GX)r_jSj=%5#LT~yba`Y^F>Zx*IZqj%B z#oxMHSYGkQg1r0@bLDjWn7rZXJ3)@MTUpBC_?Oa=h+f(eUGD_zwWGPgE4_Oq>@8ZW zn5RHqj(_)Eaa2m{ZN(B*m3zy~tDXN<)BEd(%PuX!CD~VvAqVfJiQ3Ho-t>*3fHbEc zgFR9YVYD9CH$2wI^w%c^n{J~(tC8lze%b2Su_x5X5ZgM3oiggG34wvAm%qwB&2-Oj z*-MD`ADt`|fqIHBf2KPO`deG~#X7sSQ^9G>K{X>x_XDsRtkOL!qc-!yU7Qsro0mg! zJDF5P+d|nC>C+mw=s0i+{j%vU)$1n)ZTJ5!}im-F<`4GBc)diV+6>xvBoh zr`!xbL_5FUpLjYA5vn1E}-iBV@B0~7U{ONZH7`Ixo~u-%-R z&()qV2Bm?($XY_braN~#iOU6lOuN9|6$s}aGi?rGJ~)OWr25??&S;wfPp?>$XM+gjfYN$ZBamPNsX5E<826UAbOhNHka< zO@>Jb-Pj{^0SxQZZ`GDi_z8#k7|SCZrXUe!gl!?fx$+u|G&aJ)h$?RBK2sB^C0x!S zuyT&&X)!Q3iKt?{go-`bh%v6oYEw*cNT|@q*uG1oo5h)?7~)!*i$R{Fb{`4q4Y5L$ z&;*WXNu_6r5ej9wQI(_iFj(`B_RQY+X4W2c8tF++OMX5(+JWR9ceMRkQiyp`dDz=W zr-8~LX0UV(K@g!y*~~hE{m8=R9o#_9W5TB%aNEHFwrPAZ{(aUtR+nGQZ@$qd+CR(= z%>`+zcGIObkvy(ypp|v{6O_n1 zmiYb*u~V$ z<@PYU441Wqt1Kp_(%sZUQJxi*Tk7U~>*J^v7x12f5wbTW`!L-t$IbOJrFM~+rll5w z%ClTj+Z9R;T95ck-mQIX-J#~hn4d^0mu=EBug}u2R&tY6Mzq(lAEqg{n%tdsI3920 zFzF0+ba+g*2VSPg!OwFKOgU-kKZRe>(fQwX19wZ?lAuL%WKD`j7s@x<5>oh;Sb)um z@!n7crocY%@L;JVl^JitGo*bb&pwe5^KfQVq!K0f+zCz*!w`^~b?Ty_*26`@7Cd(X zIqvd+wzR>I1CQq;Rm~voI=x@I^!qD_zG6LqMG7=MHHLom$}B1(&ClFAa+|rePme{- zNa399V+@LYID*v}f$ntgt30gZp*9Byw0eswF|gSYh;jSjVQPx0>10>vt&|z^ApKa| zEZai4MzFO;XflRqRDZ*s7@5CwJI+0|G}SXTE1O{sd|;T4-Zvg%(~7igizcOo2<9a* zX~%`F9O`>v8#dge6c?UKLy+tYPpin)5{<%#8#7bwB42oS->S0Ei%9f#xwRRUD1Y}0 z1bbyncEHqOl2*kdnqtB&Rd{9{w!@Ak3?-dLIfP9kOpxD4ll_rT)fuVsLQ|pp`%!o|2&7w)5e!ZCX}D_j2Irc+k#l|a>b}t z$swt~?hIT?miAK!^(7DC42X|SaUKSr@DS?DD2D2buEjH-dO2ZN@0&~ABUP?yExt+03HD8H`YXs3CS;RIo2ftH9lOwyay zyBNIy`W}YjjhC&RWv6GAN)Ne;=XHX+(&lcZ&i7}wZjF^kZw1ZI*PefdzmC7*&pyy) zf#$EdfB8GFApKY7Uf99Jz*5B4#>w2q+2lXMU~;mKEshvw$d3J`+d&7bbH?J-ddvcQ z_0=r5xwLZ9coC#@b%t_$LIevx?HGg^ht)DNa#lEn4(XTV)Ndot1Ipk8$#h%Sr_Ah=S5wo^i7Nsh5Ia;9A2%?=61L17hT_PQ;$my- zG5Oq-8{}>(~0(j!o;h z0KMnE%`wb6hE5U^hrzsHWY;wGJ(D?D->+TfWXn!dVj>~Ag9pNagF|w5nI^dv-V4wm z86O*JC6X6r+Qvd}F0}Dkw&d7e+c9UT#mPOn_fs^i8LRgpclS{4&Pim2h&(r$>9(jF z^P%11NlWR)V5skt_~2rM+5F0CaPqVfYJA)eWI$^c)8U}PPGhH0SK=w1VB2h>mdMV> z1S8w~phBA7Z+yI`pQ6O{F2Bk18iGXxvEnf)CE!_wz=4k9!7>m1In_tNxG~`N$I>bE zty^q0oJoA?cgQrhhiYyVPu5r4LhYt#>N=ig?f0J3mD$R07S$RAR2#}xR$;0&CXwh| zAm>|LuWpq6C&e5?`x~|+M|)OfAZ7x0D4^dqBWMlX0N#iVZpE%w>``X0tYUQarocu0 z!neHJ;xpyEdf9g?B6E+F5Z4vOexG)N(Dl^^1Yb0YFpyI=4lDt4nDS;gon>s3Dr%Qk zd;_(iMp&Ji6DG8^7RiSC!A50|6Ky!0MJO0WwM}oCbJzoc`2Yz&uiqRbSAQ8SH%euX zh&rn$Qn+7D(~?^DbAms-qMHY8N3Z(3oO`xpY|&5BtH`3} zv{un|81vK{;mm%!#3y#g&ZuGZby@fm?J%~YMaeZ+(4UpUoZzvvETPvMBlXX{4AF(;^ zE*`XpyxjtSpU7qP>u^T4wtLp>8FUUjc0`ok(dP_!Qto-HABvo1TVS?tL-<059%_v4 zLRyBggxU!$7X)^Z*wA%{O86Wy<4Bm~<@1p?i?E4WKzdGaSzgfQFYoO z-75)$4E02O&hngjfAR8!oE6^^4X{HWFK5Z+)TInA6fMe<#}t*W;YAxib!yXwdA;pK zC5H>(bIk>q?LnxV*zjWH5U0)2CY^r-2#N@gBQ74Ht?>0vM-#l9r^H#YN`Muj$csWq z8PgTTO9jTY#`VY4z@W=sGA}%XGHLR~xR>+jLJ8Lscw8GEO6xu2%qy}85VO92^L}NJ zMdx=Dv%qQ0qx{s{Ky4}A;Ku1Y2ltQ54#p89W>z9u{00b1epmHDOGy1WA=f`O24Hb( zOvcGiwT=AbxCZ|H2vccN6>qr~$ab0P)-bAROcrM{Sx-MRBOZ=*p%cnXEqJN5<+k0( ze0QMrzNBIl?ric@HJGDD+QRExY)fJKY;*;T;Q!*%j~o;K1@hmC($p$(NdHSz$6ul- z|5u{^$x(2;jLd)_YVeF4LA`ZTvxRrllD5|(t+uL{-;kUT6)HzO{pJw&uOf10DRAEu zSY*Hp=!epNwmA~`oEZ7D{PgQ}`q=x(1&$y2IXRp#U))OdM&&YLTmf1*qlGhwK-A$c zByeT`k8dXic|y=skMs1Yt|S?`Y!HWkREw(%^dZu`^~`gDk#Ir%5(OzwU-Brie-=0j z3KkMMT~QqQp=S=mw76@ktOG-66!lYpKhNdwc@^)@^eCIoxVq(cfmh^8oN0BvsZ6!| z2r!kAjSY$-Y{K z(=e8mqmE|LOO*QBDz9ZsXGuRHdK_I|!C73+F;t^Tsv6pBl#1(l#mg;XKodez3{Sz~ zu4pMwJAb+l2V{Q<(L3u4ydyhN0@k%vbhJ}oA3kw zcY588Qc)28(%bU)B>CUy{g0UMtvDh5ms!46IUJNi>jO)&0w{j;Y(&LPFfgLig85HU zJPYB;q%qOkMgTPZ2atetr<54L1pVaigm!Zx{q^nZ1&ndXKN5dWF|&9SgLp|Cx{{iP z_^0~vV);^u!yeLbyH|Wc+>tUbX}dI?fm?QRdKb~d48t)P#XRg$AtFOBkVrq}w6wFH z0L3`(c#&cd<8nFe@w{>Lmo@hjRV9>!y;&GdfWSht)ROhGtlU@T0y!>G8;y)ffv|e= z{vy#{mE*}-m9Blu3fj&6mj#ArP~vspW7GmtOrL+;Ge^}_gB^c6TNg?e?8ROUk`=(hNlE?bOkN)OM39!_t@rIs z*K4ll?bojx+Z+(gp-zb0-gHBAmgZ!IqX;sZBW)87HVr_#Ee0(-Ft8ELyDq!hD0gN# z&xMZqG#ZrrM$FYV>MccRDmX~vP$yalK|a(v66)#bYD}}@nr^G~bHfF=3}FV#q44LEiLf-U(9+H?AOgC-X4;y^bawm+C7hUBM{c zNVNGFJU~li`ERlf`_#>Z+}bg~y735c}`hmM0Y zpky|(!36`wg=AT!-bsZKC1A`}A}O>vggT45=V^b`$R=iI@w|S62_4l73 z4JW5Nfjs30!qfUW=vDB*M2w@w!59APVmVyF%BFdoe(>0FLft{J0w~ft_%khlifRPYZ>ukIe<=w05_^@0`Y#-Xj=O(O7JUuPlvp~7y$ zzP6+Mlg`t>c}4*un-o-zY0M0LgJ?N19$W{IZPaF%e9~3Dnk?@l)bB;UZ)+Zz+VEG= zlk+jHif>x@03KoUL7kEI-{Q6bNxEVjmu5RZ|K6BHc!ilQ-ur{UR~iyN|JY{i&eC%tg!4zYns{C z--k+{ts;w*AOMZUsd8N*2n$flNX+onFbk{?)P^O<6+~lCi;Vi%S8NX%UhdqQHSSTC z_y-oB6wEctzO2zt7N3w@H}J!rkENz|1aCde+hhlbqc6Z%zLLWPpO6PyH(#3q{}i3L zze$`MkDKcqa3CPwzquZ~e`1ASdsM;aLh+@s-l z*RTAhWE(2Q7S#25m?OL2c&ABQ*&RGINQIcSdBZG(5pyP4B z77I##f2Y|%4C6|w#PMABEZiWx4M=QuksN6Es>anzAzqkf1}sL53xS*K8mT%GqouD& zN`wRi^Yc|*MFopDjr#eLmQjs9V*&fx%@WKFwOYxtj69SD81CS1v{H`7oacwdAD=QVghqo(iH}C3wNycAq*iMPPt|lw zDd3cHwa97lI$JDJU<$b+uwE!p2oUZ|a8u|(XY4Or`0cR&Gke{@m-bgh*`D^*AUyW) z+^XpJgM4d1l1FTpuC3;V1AwD7w3@E#tL#`XJD^yF|6!=V1b@HGkKN#0TvH5`44)|~ z4y9R>AwUW^!i*N<1odJ~e$AWT*NXyN9(jZ_FY(S|Y?!=>dK7k$7@5ur!EOhi4|B0l z{fBcY$rr6^efsMW6&rCe>Ov)9qx`CMbuo^rm4Qari>5bOXvV?ar`qK{d2a?D6XL@>jocD7;^Az=ymfYpW%n|1W zVb8`-e6&^_h-a*NIB{YbSh+NcA7^Km9ES0J%f*qG(-Ey5LED= zHTvZV*3pKW4l%#Ogbh-(O;Z>(=1?CkmQ^q<tS0$(vGpb$0vI$2+2Xx2)Fs zNKXxZTn-byCG3V;y%6E}WW)Pv^&@WF)@mDZ$k^Q_Nu^h6r8HLM4gjxAan*$)z%ju- zDL)(Nioegr1UeldZQY{$9N@>5chFyT`CEF8c3L${ipFuuO1esePly335+f*w$ueWR`xL3Tn*w(aQ-c$V+AO zFGqhNElo?hunqt4u8avPK)8=BhIP`j6 zGXnDt$WuUmFsFCR$TM>zp7}HFj)2FR3U<~^)Wv=nGI&*eNH_(;mFwpPiGxviby&_x z(@67G#>~P#*21raP#0A%s&y?Tf1^V;#S^qp(Z^8< zv^9#+2Idi;Iu5Su&0qk;aIfFlA7}?n;s$@MgAe)WSHIa%foqNt15) zLAyH}?bzl_r)TLwP-@~GXkvw#$u2gFk@TXg0U!PSnETMF?a1qn7PN|& z7UKXx_UCQrp=wW+S&zdLleb@N`8|bflS2BhT&0_t@@EX*bUme;+VW?P#dn?acRcw$ zPu_5XTUwt%*cWJmJ+qjvU=m-G8(XVa(4GSYz=)pInEQbIG>(e{#3jli2}xXPSnoFz zhGy!Ov*A}X;3KigDW~gic_?F3ct`waWXS&;8L~_9B`^NkQMbPtt$*q6RorciemU6M zn0uHQ|3`cXPMJ}_kw6{kF^cL+8^Q!FaS`sF<;GN*j0Ky|m}gBYVwIQlPe@P|i_{t* z_PnZDDJzO7&?SDHl|kftAQ%mX;l^s4uWWRSmIgNm7BSjL5&c zX_>RMu|x~$zT^=z9{pXGu~95nn!IsSn_`PVOg3 zbM4%ehZ$>B4pb{}9OW4x)c30GrfZo#f(Xn*Mqjy)?<zurTYTp)2BV zrdEi{cU9gMZtbaZj0Y0QSI>cctpE?-Kx2PC(8(!?&m8ZONJ2jB3;BuXnmiOHi?_G< zG7npkB))eZ4fm!wpP;1gsnwIVoyRZ~piLpC+Y085{ zXP0dT^7fdet3zJLA{1&A36fLhLqX*{5|jYvrk>RhlY_^>D@66gd5+(HukK2cbO~MJ z%|1oC#Pm{!bw5*%W0cCWj}Q?1FozT%e_`q)K>eW0+|im5*wR2im~#qCKx8B317$EZ zAF{qB!RxOAU8l;+26^i)bDa)(;>Z612d67@NHdp(E`@&N|SNwGn7CuF-CyUPvzm60ZAsHy|Q=M>q zT>u+K`|J4V&gsC7tWt|XQ`?^{`zQf za~lIItADI=YSxB!Q(ao~nd#CZ9}|3%5*B7ALK6P*BLzua$tA9i1R31m2RUP$tUj|+ z+)!~D)P7AhOw(g2`Kl&7b(v=QXLZ}6MSXL%c58=DwdK-!O83cRHjgVgM~U~>*Ws9# z+4NJ_j%WA%-!)ISivk25V1j7fQbFXqHtWr=-X=}Cwe^gtIUw{g^@2G*LlXp z*rh!75G7DW94(L_y1sT)8fH1Q?Q1I~o3E2@L0`q(j3RzRQFllkRY zRaC~UppIPQ7kUG)vZiqINv)HvhW>yB(%hZ0mNTyLk{H?}iQ4eFx>X!2#FuIsEkl@ zu)laS*Jd=49&Pg#`v`%`o?xP1;((V=4+r5^FL2B>tQfqj-Os#75Lc&r4`t+Kl!Zmw zI25h#GI5W{&>mI=*4velI-|x)IMpYe)pd~$h1qZyOG(V^Fj!1IVjKSIwS{H&==X&m zIGe|VGN2(Em@3+)-Lv7<)NU1$Tw?0hu7;si((K;O5p0Zu^5~I|KPc#AWR?I|M-^bte&t4XP>Z6nMbre+PEXIwtLGV0LWbPXhRAFsT__**yI6` z7f`m<9Go*7%g0(1bO~zgRc4s+dk+xqZA`pdgLb=?4xX7Coemn-?4VjsQKrAfBZN&l z4yr*uh4nKgPpK5T%C9UXVhnC+=qe-m94HVjw8#d24S2XWt+N(mqbyh7S@F`G7Oo5@ zPsR7u4f(4>BFqcm;I#!BMuTRfHj%Nd6G=RlVQm$Ln&uUX*=bRqL?`ML`T+qq)avKfP?P;z^4l zCvv-~;;jf}MnW#%<;6DJjmQGV<~B<+Qg-GWR3nw>k}Tw9m5#l+t9%T{ZZ{UtI~EZWpl51=nH|+*`Tac#6ffCi}`irYHsc zWvO^}t13AItWqFvUG+J5hKUjd=tY1PoPEd}TL^Ho=EGH6N|-bhBw9$8L_*{!Q-_4l1l6-u84R3ym1Z2Ipd!SJsXpwf(gWuyCEcs&^gjhFXh`#j zpX^YSnJgh2SqC8!7C_1;gPfpQhX7Jw2{Qedc5pRE5=@tE{fpL+)GJ_WHT)BrI(=`_ z71;8MYL`lKWh79Jqz21z;Y=w*)Jzzan?a8G_4D8coLexmkO_wNoRUE@V-J|P2bw(b zkBO@Xtjn^du?y|mW_91FKiKeI(+v8Q^!Ljc?E(6`qmjdN)rzbBlF`6Snaz$`dL#Jv znk>23jecF|329GH zF>NQAPBq;h`^F&_b;s?7h+du5LA(d z3`q`g1t<)eOGYYnCN^u-HAT{C%x6E%uG5q|anNlWDe=y#c4Df)4MB1ycG9Vbpe=-# zxDeOA&>tP-+fog=iXF_BGbL|!Bqhb9Os_>6@*ZNh=qdm>kO!hK?OC8-=|?uDVQdU; zHrg(pS$MaGlQ%}H8+HPk=Lb6m2iL9i>7s_$L9-cW#Tp+(mhp|x5L%oV)d`42@E-Ey zuU|#br-Dn4i;w@{GNzaX9j#KHi}u*a>(9}(PHPSGzmXnR5|uD>vCCzXGc&6bE)23u zx6l2&bVjUqzTYrt*_N@A7@hCJ^m`9G^6V5^PUZG4hnDH9@Mr4vv*G_mKHUu z?84U|;96FWx4^fg7dsoM;+tO2MLsri%Gc9OGR~BqW=fu9PAbw#4nhs0o7he2Mfvc; zX2y{jsHICR$xO_#l=tYWzaJ+?Ce&~@sErqF%@QJV*`lnk(31T zbkQUK&5*E_I(j{Udk+(`uLj%AjIslRvO^MrAsew z9R3_Wlp<9^M`NF3Fu@dfafhrk4p*~v4mjwJxMroWBk84!wl7IpmxrL-G57YMJEzb5qx zKL05wMx|D%C@6D4&O7J$E{cKc!2u&0x1#8SU+;Cti%jG0BgghfT@(%hap*8&-W~Yp z4^VS2qG*PGeI_UoF=%*#DC7cEHbctP3OJM@Mp+cJGzRK=O;rP`BP~Nt^@dGCas4h# zb0YIVsd?-y44DKM&LEM+5UGevR9EdZN~$g*VP+F|x(Neu7>ffQrUsOrshAt($yZ^# zLdtupacPP{XJR6T>ld#s_I%J!lL?5HOIf5fX!9`v-p4VbuKPuu@9<@{Z|7<}Ozu7+ zNX{4q$wkY=C}f9lSMu=7qS>&)X%*WL44xi+XN*HVWQ+FapVBpo_WHpI7<RY=aaVc?n~XK43zLX#3WM=r}hsnHEu zH6t#Dm^W$9?FF->p`9)k~zuM_u4e0Q3`-5#7KN7GH!{FWDMbTF?2g6Ua>B^ ze_VuZP~aA56)8TUT!@vd68@nIt*ZgN3{loAy&f6csE26}FeILJ(cLbPWEbF8)0%6J z{H%{J2J8GmAI@5sG?~i^FDf$NPv6dhfqivY#cE= z$`QJ81nk(C`eCFsoB|J~W~)KmYK(FU&EQZOdg|&iA~4GH4E*MS2M-q9hjrI}EXQrG z?JnY4eC;KrP`JHdk|+UEfL2vofXih8p2mF4R+ACpRa-<(Q>wv}g?N@FQ&a;0FaWx* zjgPd#bPlksH_I}gF{Jbwf#W4v7J?~I17AuHZ-kxb)JPA|X-7ps7gjC%f~K=nZz zmj6XA+#MX_OQSqw9n?v%mPB8V2&zes1S$EAh)Ij6ANInZ|J@7H+#lqjgjsQmt%x(Q zNK z9j!g|W&F2Jb>Ov~TZr<3MH7RqpXHQ5&rrRJsiMpdlN_OZ|^0@P0Y^g zq`a22+84&!F9;uFk+UQ{IB9`VWh{RZsUqn@K`2>j$t%4hA~&&Oq#ap4u7V<7KAk9s zP)&jP#4Q46kIUw`RC0kqYKCPKY^ET^A?pQASBtQy&+4p_f{Ud$&Oe(LUHPhC2K~nksJA7Aq>G9Uy5`(bjCVrwPt*F?UTF=>d{8kaA0kja4$qh;bg#MQ@A||#5lMU>Y0-wcna4t{7JU2 zorI>W<&U_CbtM#I-ziIA?Tcd73znWp40%a<@)m#RHzR%`6WP~jy0XNt@ipT7h8(u2 z>%0vX(FZo`z}it$(Aa4N8&Evviia9O*}Khwsy08Q+hb*hDKhm-YJIRcl-Oxu4Uwlq zK%m1n&j5YZ{t?lHimHMzpP)4Thq9W0{Fga8Gew5+c8E8`BHHkKS>wJvsoExqZ5`Tk zS%zDJvUFlXQqv}TGwu1bc*3!8Ly8&EkohEo%)7l{{2%X+-q}THxyKATxsUwG+^2kE zfjdI!dt3M;?N%C72je?m)wy!zPJ*%SyH*lD0lK{>BoVw}<`R}(jb4+#9YQ1|6Bk(y zjV?ptKVW$oL$KXxqrV5we8$Pw zB~Fxs3Z^c{mkLO$FgKD^q*HFHms}bqQo*rR!s)&#wF8viiF=)V%Uu~)WD7T|l)GRr z$(OEUsq$>7R}ZMZ8>w888(E6+#hEyb!J}64gJLnAUzGU(FENOQw1in;kVxnVuK+BR z2z+oSnlwLAR6aq%Mm;3}spFwhk;bdkF)a-8?Ldxr^Y~s z58IKYFGQZoylC<#+;ruy?}n@U1D8d!`7>H`E^YFrP0y|Jb6?GEXaMWtkzW9nZ$4AS zRXLmB$#D+{%kD2Tr_i31vfAhI+F99-V%nI#C3!$*xFxJTKytk`;mJA*Yy%70B~SJD zC_75m&f$?VsK#1PC{2DPBJU()GfkKo#vS9pq6^9l{(gIe+tZJkrIs5330dCidS6I= z)hfhlweUT-IbYPXSmg_pA{S8L%}MY#`mFWmS-s!Eu+B98mlScJEewMao}5xbqVB#V zbP9w}I-luGZ?>gh1WMm{i!-F+7osUHVF>fV!0SI-e8Jpzdp>zq{(B;cMGo(i4j z-`g=I!uBYi4+43q@f*Bzd}jxl=5~q3dJWv|FByO>1d0Pj+QyeDCP^I&Lce_-%eR69Y!PkuELVd{9jBj8{YL#^j zS^r`8@0l>V;DdeHBYz2%yPd(_9TDwCB){YZ=V$4@*r1PNC1yH@NVj<%Fgv_~Uz0w@ zv@K;u33umN;xAGnSSVBYwOGn}&Vv2O75xU%zOHv>q31x>J&ZK2d_`kQu2-o24pG?L zqZ5T=g#E0t(1zkN9L#&Nqm>V~abb@yJq5YP3wJq1c^DU~qaYrBJ@~gRKJX)2jf+nvZG~pG^Y~kr*<>8pMq&dX#$3<#|QFnz!YDH;#BMqOE zrBxvgpS>YXF3Q-K=!S5QyT2*Y8oIah!=0R>-JT}@nhhN&)iCJNjh1_ZYPu-213ohK zCT*$jR3V6_d0enVJJR)rvstvXPvl2`f3RPzjU5s420=JWoE3XT@g_!S^h)|9SXLOB zd0?T9c`Q5A>}hm=(k=hOfV9h&P5K=zGtxz!i(grT)1z?|;r<8u8&emMbN5H7llVqT z;?`m~_eBYdnxIcd;;zO+$$KUt##dkVHJ|9aU>#z~HE-65QtLas!c{hGCQ^WY>v+JX z-?1!CH-Z*TQJM)h^7TNN~GxbUH&c{3)krDTjQ8b;Y?-8HoxO-euv+cPVJMkm1KJP_h8$bCD_;6 zsb&d!0aCZoJ_S4aTjiy%9SHU3QndA$>+%b_@Rk&3SI?yCHQ=dF&*1Kp9%` z+zM{|e_KKFFFp6tSVQtJJoj$3faYF!?&5Fwr#|u7)n4_U{B5iGsu$x8-!1y8cj9kV zebrm=w-H+w#a+v#3)}Divas^sw%*!Hu)}~s0RibD{SUj%{>wtK>{M7Q9Sy9J?-Bb; z93Jzm&_r_iOjhf8Qs;AaIRZ=ks;TuKrt`F8$_*4Tj)|OzJdT&n2gO9-M5_>Rae`rn zsj5XFz!p?gRfb}O`7o@kN~HRr(5%!!X(deLtVsPIGk1@V*89w&MVt4XJJ0X-DW&BBiti=PP{4wyKdCZuwq3FXRcVW0V ziBE%8##;K8b#+hpz|RiG_U1wwBG%^FLnRUGyf94@zinm{V;uoS-GE_zzfr6STmWT?2qSlfFH~jcqEfV|!ZkaeOtc&j zH|iJ+lUJURO8M+FhevU`PYQutQ#>EA;(Vpd#DXVcZ^X`E8(qv;V4O1Lm$1Z*rd`LJ znYIHEM1`UwNG*pueNz zI9l$tWwg>zuAmy2NUjEyOVA`dpPa^7(w8qsJCeIvU0IOUYo+N<$oGv+oB?(zAxlt{- z4$c{M&qbVg4mgg@oO_}UUJ%XP;}j0Q7u6wLC!Q;iEyrBvycsciP}&S|ogMs})r(Gd z%VoPo(7MB}cFUpFYY)Cz;<+Omd*&QbP&|O#9fBNtChE8vpmih=;yK~DLk;J**yAz& z^D5WO%@dKrWPDB$R)` z;}4avZ${}O3vc<%U#ItY;3&I3qXWljf<0@7&1i#t3qRoJ-wB*~%3^zXYU%i(cP5X_FBf(n^i9pzA^if&8O3my&4xQ72K(X%?UM@a zLk>wVk6rv>sB|+deeGB>r?_aQDBXmX`718;e2UHKwaLk4&l~1jEO*2}mN(DFA7;&) z((+sT_-}_{sBg|{H={6Wlf~B%UpEP<`I`?uf%?q8xxvv?pX@iXh0}H)99-R^H-KX@ zhv4~c8FP)azzf>$9V7hzGrRK>Vv|MxFgjPwEq&f@v%~(8;(tT_zuPMx)E~NB*6jJo zSnWtR&#&_@KTm)0c=ng4`nuCEx^9lEJNqF;R{PZyt?OoIW}Gazw&Ts~uIlcWcITzM zD&DTSVZ{5~=zqezeKXA$iK^E8>slQD*{x#c`u&G~-e1JC|MA>ETu1kxiTS&ibE3G}_(S*H-Rv{1LG@=)*4?)yyp$eU@H)^La-kM@@{*=gRNZ&=%=g-JSIHqD2kjXhO=z%8dys!tEtn*I&X?w8pjPLy8 zbCVK_mid0TdWPHXIBUj#(HiT6vpM!PKk#LFzP%x%lKsQ+DLp^x83Mc+ndBL8ofQJw zum=JH3SbI+atId#gu}=n!Em-kyfgFDB}V>_%4cP`E;GXT$fjbRFM@2U63}4Kc_hHo zMvx7jW2O@>3N#Q#6JszBcz+?tp&;kFBMb(gP=e2Nm@UZ8#yrOa+1Z6?rh`v4LAHW@ zN4cy7&;u|U)e6Yz0GMZ=z^qUJdSC%IE09h?LAI@^QGcHp&^8#&E3XUYLp%hr4f8Al zWZUY1D}ABy01hs&hmcMtK(_6A)71$e+hBCD!euZY**46rpUAe=0@oB{+J?Ci6xr7O z4@4e;Y=zPObwXf1vaOhVz>sZy1#A;z*otpQ7_#;Gz)dC~>(Oa+>rr<$AzMFLh>-P& zeNM4J1cnS&w13wUE0a;ouARYjqgWl5s literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-ibm-j9_vm.zip b/src/test/resources/zip/data-java-ibm-j9_vm.zip new file mode 100644 index 0000000000000000000000000000000000000000..09a23e79d5116a4c0eeab765bc258f659c6c8e42 GIT binary patch literal 44297 zcma%i19W8T(spd8<78snwryi#+nHcu+s?$!#1q@LZJQJQIrpCLzxUjAzW@Gv_3qwl zckN!QpQ?JQ-l}>Pq(Q-8fc`j$+_t6uaq;IH*ypF6qZz%z|CLyd{`iXoZJ6UTqtpfmd8c9MduG$ zoB%wx`Y3nC)0KUWW>uuN^kXz(s~dkS24%C#|45X?cq3z&!DD#!Wt7^N`Ap2*h`NuW zkIj$el9I4#O6)~i=;g{>?nuVE3hGS+$E8lIXk>l3-q<8{NhaCp*m=COFS>IP&46Kc zG(<@@O3_wnB)sq`gQDm#%mr3)kEl)#`X?2ARb-9cw7EBasQv1@t!o_=2&nW^tEB%O z+J7P$rNU{4s)+QicV;XJW!BVdAS58kk^I7kVkESXI;($SWW&GJZOXnvj3f0Tx9DByLu@1tHE7T}O!muN zXrSuwI?VRE`nG!TF&s0Fy2tpgX9P&*AH)*jvPrZcJMmpJ%yBqn2AT?fR9uc-F6~nY zNryA$vJKE?!?%T4BLpnxT(;=e~s1;^a7zM4q>ucQ?6m7Atp}WL>QPA~nit!qisjK0KeGt!7n9 z6LToJw9iC+TvMSZ{mX>9U0kEBt0mh~bA);Fg(~sAW0-yHWJT+upMiY+s7vElI{|>< zPNh9mXEpAHloMrgt_vQtQDCvJG^f_vQ)9-v=LzF2iHBI+OLOLzez2N2`;YV@+DlO% zNd&6(!00fyb&>C6rxm1iYt!FpmRBfK&YX?8sc?;E4iww%Af$|)996hLPK$R}@NiB$ z;55ZUz*>r(u|s=Svo8!66HUpN=&&2WD@x0D2x4AvWd@vVipQ+21%`-GlP+#9sXgch z)gy%_5uGXHaCdo`ZuGnk+9ZZuQi>@arOJx zE(j2uno{5;jXWEFIQ7s?+Q5f8Vt+I3O{>t3J!+Qrg1NxT*NI@CT8zH^Mnn8YMa!RB zM%=DPhq&A|<>-{M^fozXIzGFiykgSUoxBgSs@LiC12`B?t;5Gs5Bl_#&O8xw6;5r| zP>te{v+9fbys7$rFVFL9zxNeTb=!2P`XBQ$&x|35hWA53lVPwKU>v;8;Hj`<{Q4sq<` z?$0NfKS`V7zdR}E;%si`_$Rrm(f4=9-6NHA-L70&XW{N-#%2`A;6q3b~ zd2>MGcZHxR2l_{Ftl{%baAI8Cx_k%H$i2+n%{|Q(FFE9C@MlP)e~=QV;jB}z=#CtM z+f}0Km8~G*zRJ)*ZOM%n8}wt9G7CKR+Ws)Yv6ZSv!?0BrHqS|%&t2*-<=$M@a8mu2 zc9n@b&`HEE)$?PjHgPl*FF+)a&QT?gUbuMzDlojf>_xaxtRxqqY1#MCe0I9*5<6EF zYRU)ne*lC63i*Vg2lA!1^YiZ`eZoNYUto|kurc{32&yr%pCBLweSIxo_-_A`dOE7R zfm%=}jE<*U!^k2Gy50iuum{wg!XbR>gvj_{bTotg=i@H4epGHqc1TBvpKnh51a9*X zw%@R!M<^wE>2To9S^Q8Sj^FhH=F9xqTolte7{S!ob2*B+xm4PdSq7=!ig>!_p@drl zRU4Qo8?=d6lAmm%GnGrc6#p<+a!griv2+DUV@C3kx*lm7Y_!6z@?q8qe6$~#TV%)sYX-zaVJ&gn)-G089!52q^b6x1j$o5GcABSX(%IkjR+0nppoC zx0P+|W)uKE7g`k67ouI1P93&X)=n-|9blO>I9%~mj1<97$30ZZiK_(wl#e8%FlOv= zzL)&SL)SN;Wy1j*$LvhcjcliH7df5$KA=l|bsQ>tC>s6g!Qk+ZD5?Fy05LcxXr_&n zFByylBz&QSwAZ=8;&9=bZ(T@?m45pSM`(mJc7xmP+4Dvk%(_2qoFAf+Pc?(>?!5wF zw|}qw(luy1cN%=?tN^P44?a2_xv0`KRd}TO`G8rU^tO4gr&r! zqS%tb%MLU3mb8OteFRzKQ7kGpt`*7hG%1scX@vY-L;AX~W^eP?D?u}4m2WidSPhAB zJit9Fp%!7c5srWvP%NDu69%Cz^jw}W!X|UZ_bNvWHxd08Ax7$=0+hSz} z^-f|(I8_LlC~zIp(wwGk>?-NjOoCyVs|vK=KsGKm$57J&AAweV^pZ`uPZhD}Y{RHz z@FybK=Q#>ElCqpaXGqrqk|lmjcog4A6io9vC6t5f!{A*)kF|)I`ee?L&bCx~r8KS( zE+A6-!8wU)%QObPC~pz}YL;8dUn_b)&5`5NGb#W7%<@l$Qs6EF5k#tZIL>%nxKF^w zqR8_@7$6HLfbtI|$6OS1#WK}*bL}q2atA^rjmGbr`q3IuR+V==dhZOuASV2S3JGQo z>?Cj`9Cjhl-U6=Jsj@bbSsp{`PzLh>k~-syacxSRtR~k)rpkauv5s}r+Md+l#gcb{ z3{>~Rfkj`0hNsh$l6V*uAoo@jDc9p`vQ}Dv&Lv7TZthzVA6^|h30z00&&Coll2nJ! zD|?9y($j58;D@yK0|1U_W8CbjgNm4;^ zqjIYPfZz`cI@_Zt5SygNMCnzQ3K$7Lp`lj*_7@#c4+j;(}%M+82OCkldSaG3jns;*sAK)+ZzL$sFV z*XRaH25kltedUExrScY)Tva?On|U$lS32}F?K!%tH(>L}3Y(-wxd~-+q{{M=PmNlf@om_!iTnB|4nhAVd3*~IB)=tf@5(k`S4=UoSs64w$m*{>%xzcUM= zRo)zodqC$AXYGH?&trKc?uRMeFm3%FDWOo-qz|d+PjApxax=t(5ZBpy;{SffrJdci zb4SXX2B*4kdve!QJP&O35baZL{oy*eY7L$Et8L@aCVWJ0)^5hVqf06iZhbl%r!UMg zN^0CV>)m6wj@?dL-{Pc0on0B#E0_DV?(ru8Je*=W=@_Qf9_k`5KEMUm)Sezv7xrRT z5P=Jwr!ODZT0dDI;g-|f$Zrce``|~A8JH^1q+mEzH*DLOps#4-6UjjN)XRAn>rpzBzU=k;?v0-KbEev_5cpxrpwsW_9Emj&vG)gLLl}s)2CgMj|N+pM* zwIgeF8d6wOWi(4g4BY!!d+mGrYnyuivDOlU2!rFcyE+*X#zmHepXhCJ!cGYm%l6wwtNpZVMZh?@gg-(;(7i>n zCo>~*A6i#VyF^mYd4*DZ2*>ZbrLHS1I~CO)b={oZ0YTQU0$+^Ba65`uArv&jJiV&iKcF+tJ!SrrI z5yDmPZ3;f^aU+g2Aqlc8gk-Ow>Z8T_Wl}NR)Y}CYoO_nt@zY9mlA)n~5O2LMi$s{h zE|GSUV&8~C$~}qOu)cQR1hUPmX>>K zFn3)SLsCOlZKL{3cw;YXOlx+d>GFbLe^twA(M1c0U4J#4T@oScIp%t{d@FfY*g1p5 zscTr-#V9uVW`!Ee+VTP{83yaJ==$0;o^S<@oFvH@5Co}>=Gyf#her{2Axm8%NwV(x zxT3(w9-6I(GaXVCufb8xll0H+0y0q}+GSg`2lwgx-t9JBmvFCMq%gSmh%Xq|fjPC| zMdwN`oEPUSq*$jg7es|yG!vAV1EKzkgmT;U{>+%l4AJo5kM>{1v;-j#0e40MVrqg2 z88D3uWV^Zk;-OUTa7kM8H44E)ad)L9+nvfuwPk3G>cKXQGS0q6nA0B|Gf5bxD|u;N zMHt5j$@w3%2S(WVtH>CaZksGRF%(*+*$~^D^d`eO1#0!rZ%?RVy9QI!=4VgrXcpVN z_PlxqNAzlVAzE!VD(({uVXKqG#0TLzEKal%vJh#(rU?fDd3~w+DD8JoVL*Zc&JkyV zwJi*Qu+T4{1>&b#&RXWv*17!z3f8{w4l+~2lC{}0T4Z?YW>)$qI`FzDUhu#!8fAh? z;w@H3YMlfnWg+?@vHZIt@VWAQhk#**775EhjDC+=Ko2R4%q~%%cC*MkmojjCX9|+U zSLCYPkcugG3OG9kL0617KQ~Mw(srWhx8JnJ$GinyA;eyF1&3NsD6$=xa}Zzs>z7~` zHRYJRtn~$OO#NDauN%HVC!~eX5RirFHR3LrgC4b+ zyv!iytvh}0ffGeaZ>>7ahHq1xvacYBg`2clMEHuNHQzT|c?>9uGd&Oe!Pb^dFxF_J z-i8Iw)x%%U6&!scC)wfJ0707?XS$A7}8jP4)l2Wy?8EjuT3)T*~HW!0j zaH&*}Y;on|n-uy_1j6rIQLj}?btd79@6oMMl?znwaWrXEM3hEIas+9`do*+m6JoN#+_d0Vf7$ zx~}3B%PkfZ+0K>tva7)ZO{8$(+$Fr{4*OnVPl5-V!8jv%RV&(Oc!ofx4`|MJ@i`$u zS492FL9GV`%VjOT+$$A zETmE0vAQ;7McP`rn&bsq8V0eZaaWm->|^B$^(guucKTvbv_a}8s4x|CXX3`B&U7`m zk^~d-CeQI!77WYOYyEnFdfeH5LE=*cb;-DfzT}>l{ZNxM?>HMtDB6#|&_4)W>=*7ZF@LU0V0Sp(SV^{d<8+n{eT_47l zuiu|vPT76=7Rni>s&d0KAd=yhR8uw79Hev6@P0Xe9#~Y%8U?OjLwbQAZXIxMjj3;D z5{u!aLDM4F?2jOrwrvMy$Gnk7pWZq$3q0c5Yb0?WMQCbY;Ha~d=iDAK>uEXn;BG;Y zZ?lFwCKHOY@fC~sV*N1AJ;D^OX-eb7Q0lyxn%C7GpH{;#ri1$@2=0oqaXhYvymvx) zhS*vsF-K+)OXsgewXmbWm#<{|6jqZGNVZ}EXQnvTEOpNdL3ttrB#MZ>*xXvvgpkqg z#D{T?WmHcYaZnfYc%+0z{tA6okl~f7$g?nnm&LxPL>Sb^n;)x=Ee>>ca0pUK2SyB1tnvSq!uI(cCuu$@4D)GRVF9OTjmlu+TM+iZK2L%~1b%(M9Df)PkyM=ZF!S#9 zs>iMA!{X&7KXARh6}qTSN)efCdnj`?j0WA0vRuW$;3AnytEDM@tETQBc-$Sw&bko! z%+Aqxt8V@sZzbG&wr#A>>$~)rH`iSeGF&w?$OfBV9<0>^*P=ZDt8SpkZJa3i=7Vl| z<`G?PZCw$+u)fSOO&43po1H+yokSlw1S<`~K5ZP8jP?%7Egsf7Y;(Q)p?5o`T@D-N&YE{uF<&hN5a7Dq#7 z^0S)%K`mbx@nQ&QdF>!qyd`gD-@}@5r?>Y;_7MD@G6*_7J2m5gn!z=~QM^lY;G9^% zSS=aO1fE6!=YWfD4TKGL#)(TBFE`S?p>y3UE#!5hPBy|)gq zu1>QI#eOX=kU&S`H%_#c56*A!W2j|9(`?@5d(>)1aHgz-Lz<^X6btMnIjDCa%RHFN zd+mk}g2kusWyI8cg}7}`^Aqus zkz&e_xV!5_OCI75;giOctA^Qh%C9K8WW15~E;P!C#COY_W+{By&syGJ4K4yl*oWzpwRS#F=D%B?{s(I*J3Cs~nyEV)*xQ@@SyfC@ z7?%QNM0zj!Zgsk_(D;rYzLksad|d&hghV5XnDkBVS8kDYLi{=!&oQ+JQg;C2mT*|Y zytKSwkFjZooe$IP^Zh&U7MLem;uO`+Ay0~8UvLO5;wo6U#_zzHv>7T+asby`FLHTy znuL(ekNP&bLn8~jeh$L|Muyx_u^y_!5C5P&z5c)xh8ijP%L)ye0@5dSE$P(=5nSn_ z0Kb}9eKu$zBa_%64rsdi=@_Sk0nMpyrFY6)CYDn8{X$3C^wI7?=4%44#G2jS-tZ9J zp6O0(q?0N!BxqiE+W}@QvOurFsLl6$qz8{M(hai7ixxBVYcs0Xs@g>}zR7QuFAyh< z+C#kUc~?CW2pzr5YEF%UXt3z|37n=+RduG+jk%(kxng>>Vgr-D@HG*Q9ClEKwrr;D${S@S~}lbip`R9Iy*mr?4j^kti^MJ zahfzkY?@TXOZfwV;RBi~4J87?TMZd;dw9_vSu6SjkPs|bd`h;Fzm&V@P5gSuQcpl#F9wxw_yu;`5{eRS7kkB^ELDNAv`0ySf2*~K*L85dxCl;Nki%p( zIHTTql9>k_cykO3CQ&au`S=-TWd`+k{g=s?A~gAohk`g+y2aPsNwrSx()?(S!J5Ruz*dqd?+{`eFA>LbLhnH=iJ>)%dM7qSv@XPlhdfyVQcF$@kllsZ$eOOY3sKM{k_}9^Cu=8(-}oQ(e`@$%Y4XV z$YK|2`e-9b?7Sfnj^`Z8A*l?Q^fxoP<1Hy&jq(^{4$~+_wi2^yV4B+?jt?d7bU815 zMS62fP`Qn9%oJIJ`8L3mDzb=E>A_jSCsP++N zuiDtrMYCP+IdAv3L4!kMp}VvM*G-yAX=9cqfH39R9HKNI+0$LDeiLLnahct5BF+ia zb4a^^o7Unw$q2lGHa}_xL;R&9%i$1|utjN8d$~P*LjE46 zdSL$>UqrG&%=2z71SOp&$FjOEbzy>Dp$&@a^;uRD>U=9w^k$j+$MXW$A!fi=_6P1`d+|B|^2(O4#W-odxIyC2CYKW(kirOt3HJMtdt z>d$tTx^$!aEcbr7p+E+jOn-5}1>kErI33oQn&WM??ZSe@=>uCG{6IiupA#2V2X+zq zso0761AfPIJrYT4I&gf+*L7x-3ba35zh6L!%ilH_WkwN~SP0buZxA}IM=~={Z0bp* z9_bJimL+xmdJA^}VesMH4!$1T44JQRfUPXqU>VQt(A2-~z#LoIpg z4p#PsX7U9#R)NX4^?v)pyZC>;ZjV{72X#>kbxwK2<85w@TGH(OX+-XxTQB!6fVkY1N?t zxCC33Ic6-M<;7W-b_FXhe!a>qSx+e=x}mhi#|LB1M)VsfdFXnGbko5nFV5F{6f9E9 z|BiVTTDOw{P-UqtrDCd*InrFCSd*OJ#zzvvU>0sl+cTrs?f^ul!DKmyx(agzpySvny4h{A+C%aZa(mr4z=?fk~*2R zf9!7as>PD0nU|&vC9263iiIrJI_iaOFjEz!5S`m`1*6RMkH{20SF6Ix1(!uIDb`u5 zD_U3dbHU$CBBDGFD*934z_WlC+3*NNL|w(o0yqv04ejpco`dVe47EtP|4Kv<MTb^-ZrsY3exD;+Iet@T^L`g9Ca8LKv~n9Z_QKWr(e_9g@}iUaR+&S? z&ClHSA3uyh8AS^n*CpzWAgy~$tFRl#aNngaJ#=DHFPThkdGDOScH1nx14}Vv8??Sn z=P{|uAd4y@&Gy&V-W~OSX)wJrG-bPTMJbCVJ79hVd8ZZOC#m~7X8bK~5amn&|3S$U zbD5(1m?MlsFq_907vjhDtKM%!A@Wg%MnfF9Y;5C5n>(#>cW_6|J&pcFXDG^VX2+Z$ zf^S4;J+=ikDLkGO_YBzs>wLyd=-<)1k4%azioVuu6zcZkI>}nepc!Rbz2=pc%q&$2 zX3A%>7Mr6RB}whK^@BKm(CuOe@1_^+Y9%Y@{$S}T1<0nU=HV8rLa>asMrXvMMpN(c z4$6*BIhaVvp#-(b%Zzf>h|3`}*9vBmXNYLap&pJx_JP-m>QJnTP;&Q)-Vi#}c!``P z#e_-kp&I6RNu8xkX67}Fy;gJIqrfJo9mLkWp`jP0dMWOCFdk#uK}TS;5A2Ls-5tQ6 z%#FOzIz;jFx(iyV&5NV4#;yG{W-`7d`8tyD!6*N?6fZJ+Ukmpw&Q_BTZ@QG$8%4A7 z!%((g?<9IHEDdv7oH=VzBRi(ksv`9{J6ZS_+K8zFo`*)=SH2b%uZov`RYJ9i=wV43 zBD%vL6`6{rm#^#vy)8K>THaeGAD5v*ZLD(k6EIR?{;wA9L%;Yg&sVcvr$A z*cFo89F3>9xc)`zEWCDLb8_^a!t1+rWUu&)MPg{nH{Zj&rZ@>jHNeSpcEpYvQBXd` z+%7*xf0jr%uxPFi*FjzhnGzfo%zZC2M!!2zf8$YHC(85JH{gHqq2y<~VBXQo0`IeM zQ2$x^#rxYd+{wwr(fOZ*=#r>uH>-dYG--oQJ}?zq3#hxa(15G2FtO8wL9PU-K)X9; zN}ufX4Y|f{iC@W)g7FaOx#vm%{J<_>Df*hDPwNF}JqFx(m^af-GhTncokRL2H09?< zS|W?v*ZUfAMfXzW1)^fhq1#J|f5{(FfyJcWst;!7g3F|x$(&7d)9VGt+ifb@jt?FM z5r#ZtNEF=ron=1*e;!Pp0kV@T@SeBoKwM-@MO+864Bbfy4q;_0zH!=!!_+isEH=Wr zS<|k`Z9mTiZJN)?4p>sV4M=9)tjFb#RU_#gYC+!}0C%+Xh%Zf|od4R?Rvdp-+80CS z6ScWT4;V_&t3|V&`bs3wHDR^V%_1SO6;_FDBiaVS|0--b2zd?A`z^k6)%tM-MkHEdF zTEMQu5J8v3GGYR_WVG^Ae9xBzzxK(UNritULha1Z>=WR;1z#53L$7}4zCj#WL4o1l zy(haxlQMmPUns?prg-Sd7+=!{jJ>w{=rl|(lg$hIWV?cjrbw(oMeMHaaLnQs{j`B- zts!4%WS@Van0B>KYK%H47un=GdBGTZ&|EP9k&SN63b7i5nd%1A(}QzDA1zT$HC{4& zNtM><428d(gx{{lxGQPc&Rqer5%iV%nW@+;`i3F5ppwR^8o{nA!Vgt==;_=A;k3Q&`Lz@| zlre2!w?yG#?OQe4ND5N=uL3dkrjM4&-<`gHNc*U?k=goa_MZZ`DT+)-^mu*vB}IL& z&}gw2cUaGO2lb}6R1Z|wG`vqf)B%Ayw%POm_pbRy?(2pI=2T>Zb(~a`Racvq@0miS zfS}A!PM$H$DK?;KQ7|ZrkG;9%wygTN0`q!oZR)P5EvV5J<1b)KV#WP3V2-K2RmU{p z^P+r_Iu7ObD8HsF{{amB*=Q)TOXxTu7yb#f&2 zZ8yJM)-$MvYdlNgE1RSl{3^<6PthV)jU$Zf+2~4drIm8!aD`1Hm+6GXIh&(eZGeCg zn;q|*OmSU#tt(fdfPC6;y#WqFKvCtdQuVcR4S-X0yTn@k0!P2OEKb_?LX+_AHo{{? z)HMl);xBP1#|90!7X}!i14o|nY{NC;2d?lC8&LxXMT+HfZGhoerU4@CkM!;|+ooa= zNzKtq$u_U*6ruEG96)?>LipRRg{>;N&8)r5;se1do1A*}4+}C&r{xU5K@n9_l$p4! zS)ew|gH<}RHrD6?6Z92h6Z3>VO3>roOgxx$I;fRI&{^uRp|MTbe!NZ-sR4t}>R41U zUKv9)0J=NhUio&6TGy1e7-d~99)VePB9Wz{HWS&8Qs#joVXXGTLj#?Q)0)d$EE<^BIz7F~Z{BLWKzQ^!sRIGE zYHCY5Q?LwDoag#MIV~g}#&lWMuygKwy}Rq0TsovSk(lg8Z3@GT1B==T2d+0)v_NO{ z#_sWaRUe%}}uFMoN>YUF8kV6UQGC$H}NQrn36iLuTkxwO2#2x47b zWW29C)Qn!T5aI|^*YI?P=~45;q1e;JTE=PxOicVJp#@{CTpj&xz+OLhAzz2Yt+-f_ zl{CSVnhk@TGsEh@p5)u2dFry_=N}Sdb+M=|#IQASnG`MP`dU}^>6wS1D#*v>htKRk~am~jhHj8<_ zWn$6@O@Tk{9PGMJ(HXzYGBA)TuJrQ#Uc?Wvt-7Q1u`^ngT${#e3vlg8lDCp?0ntDD zs5_oW5_L5!&*dMWD)(Ui&FT@8^LgoxKO~_5V7|SHUU9ImN_HJWJSKz&R#SQuz1(RVIEFT(bF(Z=bTK)J(^PD!~Gym zy``^&=l*@hhmJbnSEqhG&5SKrQY=j$WGW&7Zy8%*Vz*ZZ+pw;O+na%1$}>?$9Kr5r z+Z@41rtrYM5}|k)P=kiCb^g0jDR)y!nX3HotSV_CWCv6etAcL6A-fX_isD_rDShWj zyLKJ?VM}C{eZ^;ZhM8@!8=k#s!bfxRn8_Sh4_g6=TQOlyp+j8-C!ycBy9`G9Vi$z*D z^!B5`+v&}rW88kUuXLhuD?6sBB*(|ZPu}{Y+aXe(v#tiL!m8pPGS)-6_IuH6HIcja zZY<$J=7ERQo#iiK{2~nIuFipb$72^@cc;u6VxsEP2qDBQAsE2YkR29oQ;rpZ(aXz* zONdAGM0J2C<+tPb(whjaaeL)DMCy8g4={ zPIU4-HW^c;yn7wS-jv@m^)Dcxvv z<;m9TpEzMa0P~ThO>|ZR-XjL4cq%z}G-}=iuWHyV?bmtRc&ncGo5Pj4K{_qfq@+Lh zuF4H2hM4qAj{1%R`D^^+^A2x!lOrg1D4RUyM>PL@PHujUDgjc!RSAyn9uuXpS#JCaUm{~0B(C?rEbLt7xkR0LG z+a<+Q%#9$XzI~C@Q3iUX?Wq}Rklk;34)S0sQe8hXfbuSOvr+0K-znTf+Y(-}uC8B& zbX0y^zs(`rxeVTFbRk%stok2R{SNn3=+%p;5*J7l@HHGA_Jj3@8BZJiBi{Q@kg+RdYblLKZQO#e(7)T&bB;FQ1b56-p{EveQUA7^yK9n zf7oDZM7#S~@jvHKCpsRdwaa6wciRLblIh92zY1Allk+IjTH8#GQl6=U1;NE9ITKDK zd&=e;1Mmvj@{qm%aqg7j) zem_npV$#;&tap$&a;dgBkZDBq;SuhdsHuLoDnMPOK@lt z@pmrl>TK*^lAQ}5@PA!S33n~Z13t@3AW%R+B!9P@5^^*#uoAYjb+)kmpOL$)B*`;a zMcl#8+3zWeqUWRab9z?iFM8S*NH6HlSTYS+>2g6xhWwIH2q-UV{-BU3(BzN~WQ55H z5ea?c{ZA98m}oVP$DW;!8Jm}He4CFx34AX%SB$=KshA>AZ`uYx5F??Gj8Fk4aB++( z0}NQbpb|rv$X!D~Vv<+#(~cQ&P|y1=;GP_0m=*E{c_js!{uC)^XVg7Q88x zRb!ax?XH=6PUUJzNYbYR$s&X~L&w4C4D)4wxOtk5WV^NHemYkg&cVH^c0=At)7hH) z2pxsRYavOXjBq(X6`AE`kd$(jExFF+@YyW{XB&VdY*`2Pl_v?iFN${s%2Qvi_#k$F zfUbM!B=9(i&e+u$rC-KF+OQ}$ODEvG?TW7kZDL z%}1?F+7ixN$i-S+Rb|?mM!nsD3HZ|VYz;$m6Q{J{N-4n7wHdn;2%4uV4KsbV?aEAn z=jfgw^)yc9vdx2duyGFXpsNlkhjgZQ0KPzrbZ-EIc&9zYRJKtGvM<8XP}*a_gxn3K zm?wvPGo*Y-^2^mqT}<6hJJfePJhYrt?Ny)7^OT=?Nhk<a3E=EWG94&?{Ek;b=psMJiR^aJY^NP!3XU9n^xC12xDTb;H19w_2z13cE zb+&xrE!)+Nf!7{z?AO1&F&}Z%Z)1|0(`zw;+?j6k>D=%B;)l55PHcjP>vq>lU;wFO zsDJyDOGL}GV~Db4m5C24v^R|@f9dKvf$!6utn}XN)t(zoo|$Ff>v!TB zTj3i*;+a0;8Vuro#?oG;fyx1gjZtXp9!cwdi<(jWvZF3Mn;_c8>|jfS`+8N_atvC; z^VIT>u*%K$N;{z!HdwUEem8?SJQM(Zx3>6v1exk9=uY#4Ahq~9N&UWi@X5ps*Q9o9 z7sfS_5nbFaHu29N^i?;a9nsrO-K(v`kB8{<8xCmqCa!j3jj!%8Re4xdc^x|{FW%sP zWtB!?8WsJ|KB@3$gP!*9Sml#YoSYq9jGXNpKX=Nxe0E4xJna9R=#Bc^BG>!bqF*hF z3M-Z6ufT7B6s$h)-s(nFXam3mDFsPfTC~(tGE!zlZB5=NfFZsEeNW`Tk-8=zg0(Z< z81rO4J6wE$^mVG20ZcLcFp%%=h!)0^h2Tva6w=dSVo1qF61h1^zX2A$W(x)J7>u=Z z8-UZI&vp#HVF-Pq@J_eCK9UtOEbCo*?5QCKQT-_?I}s4rZ9n@NIcdUbAr$*W>F?qL zmCKnU`^Pk8@c7Z!;&|fZ=%Z06mA(!TaV}HX4OO0(p~|q!1x>#AttdQmdN*EW^TLuf z(gJd|m;7^gL$~j8q%o~cwgdH8oG!>=FQkJPatv{2`O%M@oB$S-Ch02~j56y&=8E&` ztfH+i5DW8aLoVmjFwcwDwIUipVj4tigx+b{vRD#X$0b!tD%lMUhoF>BIFkpL*;W;C zW?4M0%##rJ?AcVKwq|_`Ny$Z209iv8T!qD_f9t9KQBQ+8*3!)XRMo_%s{VF|%wJUX zFD(VdjsG!s9W=?|8X2YSvoe!I!ctIQpvRJ@3Jl#xhC-p#HxLTWjVh)Oux4?Mb*Djx z3Ij*%5+t2s zR=mHF6A<~GsKt}@HwqNKy$Ez&m<}rG7v&T<+By4>%=>t;7@KtD!0&7eR-k0XM7TPn z@98}Jq)P>FXGtpKj=a^WZCRU~lRP|YVjfC712EBZt<#LdvSI_$Mp7Cq5)NDo5M9SL zJ{G|;UFT-e$R#80;pLW5ukx)6ARNi3izj3a-!uDD9Dwj=fs3{*?g_g<_*%`O>o>j# z>hIqdnL87zE+5Mt4V2T-T#xJeK+~5T=9MWp$qe`|qtifD`MAR(udr8FrD?hkK7BzO zz|L~v!Wk2cIUayJU{(Fc`&{oBawABz5+L)C=(spyu^llZ^+8;M8;*A;A%%r9@q>hY2C5@VQu}xxAhwB!Z=fe0UnveZK zpPlj=6mo^kaOTpG>nR4$Ue%O2h^R^FIBLH{$!YoFz9#!S0|H@d3NEAHd^Q70owCK+ zu=cIat(x5tH!u(wR|t{LwMI;DDZV;-JDyo<2NSdw*@G^Nui<{Es_Wz5iqSuk%H>$< z^Hfhhv!~$C!r7OQuKC4@3-(Llz6ku#4} z`(~I3_c`80K|9_#Em<5=Uk^1236upd3JwlYAUHR2SW;3@P-PGpGEgw@75&B6yeCCG?a1KJyoDea*>XE6DJ1`I|Sk#3Pj5}e2LL} zGdJ%;MH@bh`65{Kko5xV3k$Us5*`loagiK9B)~btk)S)le85YdLBWCLvY;i}492&I zOj5)6qIrUCL|B7S!mxnqCF_=_f`AzLf51JYGK?2F8`n2eknO=OsRy)ge5IgV835~T zwy^q@dA_lPNJjp#n3quVXs` za1N$0L+w!FBLR&kVitjnwXb5v5O*(xH~Y9 zP^~IA(5z64pycPtj~!YxMZp97!0ykX1{0ZI6Rv;2z#g1~^avCjHK6ZoF2^3#e>4p` zB)-c)ESRp3%NJqJeb5+UY-QmtV(am4dJrZ9W(VbD zfY7PZ$-D}`I)eTq3KNtd9gb4)Nvp=PeAFi|=?xHJ3{-5BTAaSj-Z%Ct?~s}NfKdsB zu1a%9ABw&xYB`B9{|g?nE^5lRV->E#fV{y92XAxQw2oe9oAuuDMih z#`EB6j>JOM)hIJ$9z;W002$l?u3rNtZnU}+WJhg=D132PyJ9q;eJU{otO)ytcg9m&WJYPE3` zn&riI@@>Z>viDB#4WgdFo__IpWGCR3MF<`&v1aB&+gy9W{Be)&zk|gugq`_godm`a z1IBVgxZw6$#pDad8rivptJO<{x5`(DF}Gu1O*F%fI*5Byaa@+fygxW1Wiox)Fjx^6KUpC$S=Sk{OwjzuZyEup zv-G3MI;bk^%mdWt+!S;aH-#KTy#u0u0X7wLV53|6K9sK&Dfl4z2Xmjm06DM4h8Qkd z;qqAFy~1cYL>FJ0<5NvLu5N$L#jx6DJRILLLM#j?Cm-+ixMR1PRewi#I;`1~a z?dgIpyY#JhCA3M}q;fO3DS>~DvXsqxXPv@!Y7Cychy7PJD3=^5_u%?dx8gIsfcR|L z;r|^=irTu^kcj-x6oa?&A5-R-yeTeL>@bnn2TPctKX9PH(Kgu}65utN2y=0Yrs+-Q zG?`ioRwZ6B-jVo+B>K!*ydK1{ay%C)D5|6`Z>!9x;cyW({Gu?#j5V22gV)+H!Qj)c)j#*8S=-KLMPA{TRrIoD>)de49;#H4*5jD;_ckKgBJm*? zE!G0|72ElhdXF}O9IXR*6`eyjQ#DcG45n;mk&jjJep>6&rYKTGGKNy30m2D`aAE&m zmJlo%COAF0;jNzwI0&McvPE=f`eq+fWsMXEOPl4MjSUfIq!(X*m+_z6SRS8I>FzoF zmP)ivECvrX`ZCCyeZ#SRT|da2*_-g{3v`0o4?pH-kUdAk_+1FETK&I3p0) zP!GRgSL)ln)e&m`8*wZ;U+;H>Fr43XSW1DGzu;gs_HJJ@p%42*F7ojS=xGKfkvNVG zQfkKPgi%?k6^7b&NS_6gUOhh0;*sOL%@pL20YoIw)AWHS7={9&-M&b|LV+fP!9k%E zLXl96*cS^?LHl+E-gqrN!E=J0wolxcQ&9qt!Yzbu3>7$1ki;#>MY)V`fU~{F=b$O^ zqd_aFliLS-NH_3JVHFjIbk9($A#&%{D+~7+SogL{BiYX zGfmmX>W@towh64V*oS9&^<3)_stE{i!Vp5EsgW=NTYM@n{qnz-8;T0pOFJ8o|-uoeXS>LL=N^PDwg_7DnJm$Jb0`tr~t8jI|jQi=24DSnj>TT9^8aA zG0Hcg<~HbLIllUIK>FSPAQpQh$GnnwPQM}l#^Rpe;|1W465g3!i|ZkD*=K|}&pBJ> z)x0?M6%r_l3~SAuC;S>)W>BWNx>5q1F$_*5MMB#Dnmc=o^V&?y?^uV2OeobBS!Rv2n=6Sj@vWhjmxS1TE_%M@HZ1(5&W-8=}c-MR6=?j(i8A7(m~jQx`xU|QPKy)XuqHiyACm}8z z=PWM%oVn*a`TMWfXuE3-!lI#GWvnl((XWr*xVC#tFuV23RDt{}05a35sNEk+67VJo zL%>=`BkHw@|95At-=O)pJ-ClBBk+XP%5}B*J;M|ZVkN-1dGAHPyR|Yi$KfoH9m-|9 zm9M;As&CeM*=oJ%9B#t7a>Jwhx0#kVFTRTHjw3)XFlSP6oo2O5KgzhpxN~LFxYzWh zHab?+0WGloJ|{oH<{{cw)E%z1k`r{tt#kO@g{~Z6iK8%iYllFocH}`~z>;0p{$8p%Mk`;~A;+>*!ucS75jy=y z;jzvmx#Sq1TU-U8TvHJW4gG>#aReua=d7OyO;60J(W@I1l z0RC&7VIKu6g{nh1$M78L5|v~$PC#kMG2K?~uq7_fw+&~-frMmxW=fR7N8$mC#UVVJ zU5~UfJ86$cSt;iRUmHOgAjYYVrjZhhL@Py@kC$aaCVq`=tX|gniYvROYm&EF@E2i! zES^99F?M8M^O5$@jfMfA*a=D9Y&=f2)R1;KKb(hifIBV-^#yF?#?IU7 zn4PoFI-GWHcAUMW5NJ&coy?W9-hvnS%T$U?mZ+O6m2gZnuhO~#+FN}S#h>6yhcC3o zj$b7w(H%BTuqxJTnm0B!8{S<_C-XTY^Yp!EmBv@xV*bZx^H;xp7B^IHCnAA;mMsf@ zu$9|CP0THZUuFCY<+dlX#RifbFi-GO*$yuP$;CI3_yvznkM?$1C01PFT6>ha!kYPnb`sy1r8WrO^TC1xLq+2;#k7do3Xr9;Zi}Uc zFT{e)1uz#74~yfF!bM!)VUv^`w5v(dWb!U=Y^>CnL#Wxj?x2XQ?VqJbbnBl!u6H(~ zryQS6!OfRP(V2Ug1D&arE$Sua{(uCGzOZ?ajXUXq4T5Q}O5Mxa1^bTlF&F(ZW0p&Z zhS_1+XA7G&ekXw#+U!RjdtnU66Fm+HWavXr*pSAmQGvO;UynaTBbRbf74!4jhnnwt zfSwQzBPI4x-}e$eP4#aJ=_1DIpf+)Up0OQ!$x^zbo*5^|stx~{%(V)3LiNIv^)4MP z4YU3;oLG@tA;V8{>z&3wxGOzcS~8qa1brlr4o)8Hgk(TUtT&Oo+1k*4!p`b(S_(Jf zm3U3qvZX?*SA;r+SGv?m_Y|8<91I`xH8aO>;{89yU;osmUD@&r>JUIcny}w0WdAi9 zE7=;`oBtbA7OJ5>^_{OjCt6yB{_KPKWf9_DbF4XL0}aBWQAHzkAh`eYLBtRdk@65m zF@WwuLLq=+>>@tdLT{z$EPcwl_m#YEpC<6_@Wd1{)uV?JJVqbzp;KZ~>n{*F4IJ*G zGoDm2NEyG%h3~j4>YE}7wQB7m(l9EHR1dAgv4NSlup_P-^!mHihk(0ooESL`({k%a zo7r0b&E0&8rkDqP=dw=rC_8_=|(K1P95;cNbHGY z8eaAz`~8dOt+Qwp#lL<##qRI40)ZWmlc`H2DNKsr0U2BQqIUuFG!%-N57RME3V)B? z=a+}X?N?rcxp=a!#Bdpe|ZAiYi*3?@v=!XU%mTQX9DJW~x#kq>yZl z>pL30(){Kw$%|x~uf=l_&D^Q8H5p`UH-?7;xV<8**ds!q=Az4A=q+Q59zceti2WgD zlm`&*k{b{MA7#TEg~rJe8^LmD88`jgg-27HO=WrLqO1rBPRX7%U=45SsL{_2f8r!8 zD)=zZ1UJa8XO?p(EyKkKIWD{D$&rXG}qgM z8?`PH|EIXr6*wde&*dio} z@HU>Q8*==@;mDeajMDUo+%ucnx@KfEmSMV(C1`pB^*OzXnfWq} z&&FA7ZH4p=ZdN#YaRg5A7`a|Fq|9tg7rQEVht zpiIy=oW&M@mfW9q0e)-yp0>D<2r_qw>^(E-Gr8gzQLVT~<&R`v;SbneDz$R`Cma~XSM(glU2`c( z2JSYG#$hBhF&tIC0#2VIGRf8Mi=AI4sd>qC&hX-}TSE06JrtZuUEWu+RKm;){0@0$ znL;mpzcCtWLsfLB=?O&!?*bQO5;@MvlW58zuk&0MG!0_NKaQ5)ZK!^NnwzdF+0UVf z^L)OXJ>6H4lW^qe;TBK@x#+~4xn#~gvlkPv4=N=XAJj3MywK9H^`pw|BtcqKS@dLr{$&gcOPl_U3cOBx1{v1+R8P4T4wN{HOvDe zhlH+;O^in6t_Up7P%%kzOOTRU-I8ktf}Kppm|4L?y&g1!4-lbDS0W8m3G^20(-i07 z@znpU%2Y4Uq)b(V%Z+6RIYgTeBo`$$W4#%LX>UcTNhBdi%$V$ba-&i#!-x^tm#`*! zFP8~b1`$MiSbY;%o2!jeiQRA31yXU&;m%t4NlykI^*yDp_LOsp7hwQd`E#zmez@|G zdJmU@k_zRxTrI1up_Q+MtfZs%QiX1y%ncNxlh9zTWQfJZJsvZ8f?)BE&&`#mT`YS~#=U4_IYyc&8=8{Ps~n5x7@Ji} zwab{3N|m}V;yGg}7w!=0*kJ4Zk2iv7&#Q3FN#L#s4+IoI1O$Zhzr7KO|DzmNtp%y1 zr;gVBtC|jW-8Mi8BQZ|I5?)$KL>aXoi5dr#xnKlbpsww5|GFTe`)Qk9gKkZpj!c;{ zrJna(OF}X`dS-2;zO_E;r2Fe@vv;z98D{XS_QQL|^Qp)C>ttAva9u$R);crTVsX6O z1t$AP=^~yBPquL>>y=AN_KZT|&(ke7o?kO3sj#*#`PmE&i^CipLkg*P&8h2W&b-w} z95s$}avcl8n)A#1+_?IKntC>cF&HRHV{ZF_1>Z-=)aR{4vRhCY9esgN$ZDHg22 zPiYxk0wd^(h=}ylG?_X@O`f^OD)P^8^yS2yqf7AI>w&Jn%?-3?Jh~*my>nbem~{-$6z8SFcF_n^khF<%r9fl!dlCK z`RM%=;hlMb8>uD2+m>h2d7W!FfaULVu|CYpCjvD1x8RTFxU*bH5`bhzA`<5|-*9d?xH*RZ6KNB#*WLDpt1lmP`fKb#rm>RJ^c+OnYXlgc)-b>~J#yqwV| zDd>HRJ;*}D6sJ*b+e3ma&L)e#Sx$1xJEC7dv%K8*BMRBA`j7I z2S$gggtCiOx7p&1SdrJHro%yI&X@J!G{J#Kz=mW&Cs%&-NW1xDd&-<=@cXj9foD<7C4q@)K3hVMc6LEfBHo1`_$b={x=xun|y9!=AHS)zTut}!>tV`w2q z$Fy|oB9?nKS1bkj+N8Brm^}w!^E|!+%tAIt$E39TBELdMYTkVEF67K?Sg*Z=rz#{l z#)IRS44YTB3*qmZBKf9u2}G_lVJ|2zl$H!eKP*4R25$}=_XUg%m~sC6{QPwpE<6}f z%GJd5syV5J`rX*odSVoHKpkv;eAz>q;2}TIT>(=0GvEhz^7vpG?qC-t)PDQ^VSXmE z|D9)CD%q^~^>`r=)~)zP(xb9LfVdo(_~>@6*s#POTdf4Lmc{x!ZYWmY9s+WbSP#tv z^BSxYu3#4)@qP!uwa+=(%^8FT%N1&F<)KNnrWx$KHw)O&a>hwS*^jA62 z2q^k$`>CgsWt*-{E7E4P1kCi{G7ZF{l|YSxD=>W?$rd*HWSFQ{c98cxXwp7MOyas) z>Wy>s!uQ-I&!5NC6xHxP2faJ(g|A^hL)guE&z$7y1qR z`$_aSg{THqoHnrr(|K_XI!+R8iEQ6HaW(JIdvM)nop69UjH5I#yoykw1-oc##?mpz zn$J=nn<&e4oZM4_9O9g<1%*c+567R2RRH)x|~{F zPQha>8Cq<+Pht4)*V1!@NIWHK|DD|ns{j9RMijLA~(oLYvrR* zT4OoMClKdcmqgE>}=4nWqP0sMYcDiRmMlc!kBhs@*&zi(=92 z^2ocGtf0)xMC|!D!29fHg+!*Yt?hnc2+Id*_U`n+Gw50R%IGd@U#d(@H}eL3IH7)MtPieS=PE0bK~T1 zDzSEZagX$&QDI(1Njx=jG9AbT8YEsR^2(ShiAvG%OEDXG{Hm+P51g}&XS0%?R^DcQ z8O%Sswg*?%UMRkd64`rgvw(IuQ+hM&xHtud6k+Zu@y2zyjLDKkzT*<-Xw7+z73T{IO=T5v9K9XVuzJywtyRlMB&cg6qr%%&vpZcHr2Wv)7>MA0Nl(iOb<Q`U)WFy!yW%ul0<6Is*{!bQ9#TM>~x|DwwD(y{61y7?OeFSah)% z5Ogb)#_^Fib$&6!mURQaq&jB`*xbMxCSfX4?$XBCO+~=IPQIA<)3-tTka-av6!P@k zNT&O{!?S}LeQB;@yis|BH`daFj`OuLW!-W-#l>m*gt36;UC`iiHR7F{g6m54G)Y#I zCtZ`B@%OGr=~DTrCdUxAUbb|ob(7*#Sh}N=&diI@X(yIh8dz=iW#w%_XZj0IhzYY4 z$uB_;kE4j*O%8))Pl4R9@uwItaqH6P8Xk&Hi^F>VjMa<3Vo@?iB9)6v#a4~*YlOrm z{c-E2@RUB|n#L-fs!nQ-X-GUvFFzYseoV?Qo`?wDREKJ=+?%y=JggD#*$#K?BtUEv^d>L_=!{#{fM633ZSnR;nsY8rPZRY_?F@*0_U8V20eN#E1f?hj?j&;URJf*l{Yx|YEtBQEMSn5y()7&P9iTgUPG^IaMeXwN7)8|k8{NEHj^ajl zB#@he&zn5F=&O-!&X7XN@m^pBG&hCU|3DI0X$Q&Q!cSTcf45)9-{0>}?EfzWE^Y5( z?rdRf`ftP)e=NT}2s2v933!US6cL(rLM#Ff9gITXFEDs;6Yoa8KHA9?ThV@eF0j?S zyrNwts7CN%E4EyTjCMf=O(5SU6*d(%)psPFoa_W1)01TO$+K`FRuNOH7{rATxpRI> zs~w1g#dXvKd>cFHWCc#rB}}&)=Nzi(kmDsVH{A4}wQ-Qr&#m^fkpwL zA(D-#!nU5A(ct&M+8Ob`@Sj!PtzAs5{xuz_P60nv75+x*TV8Q@cJh`sc6uLQ=G>Pn zo|J4hB7wr{+KMaNUJi+g!^w$>i46&Xfg^)|Gx^`QquyrMcX2g)D`y$6?N@tq1R(P$ zNDPw1@29K+Q*d-V=W*=VnwIAjM7`nh*<6<9#)AU@GX`eDn2eHc(@<}d`T3cEYaA~t zs2`{0`Kf?yoL8&U%KTiwCk})aR+(`epdSZdg;ha(*w2JG0FsV_t2}5+6W3!>ybXe_ zGYq%@;RcaVyJ0cDWa8guWup_3z80dxi+n&BhF^CJ!Jbl<5Xn;_!XP}u<=?`L9d^wv zr<5~vOfUvWvZIV;Fpb1Uow{YR(zwNKLIsxx3k8OdJJ<}NT1>VP;4H37kwu?M1qQh( zDj|**4EEkkShzQ@NQO{|$p!MoYuQePIQ5&A>*U#}Ik2uX@rqUR>x824c&c_>%3t{nPZvk_-czcS z;KURCybZB!WGli~)yiIk+pzYgL5QD$H4*7db<=-aHODMMWI6yhERQH*F-#>@xN1}} zt`sEz@s~~2%cDDt5<$QE|ua|!0`?AeSDm*oc z-%5sht?|*L8AEZ--h`T9NV?5!mi486Sj@`cv3tR8Qb_r)Bd>bs%Q4J4ujsT|-L3Ep z;Y0xbX1MVKDziHwrEWaci8@>n{kZ*Weth(i-X8RyHUf6<1(WO;sUaz?uyRtFe7M=> zcV`i)R;Jp%lwZY0>GgNe;e%C0qT}hY<$j#&GVV$c7wZIwk@>g?g5e?l1wzX6rk#~8b>nDi7O2QL<_OtI8)*05UUvL>n z2FLVJzay_Wh8!dpTS~2YRTd%w=h6e`@Vn-4yQHP(K$Uya%A6w$}As)kfQy z*d*`Ex%%e^Jl&w3ii5w-?SEK30b4}}Ha#0vu!Q^w39l&>lpv#K68guKbgAnw&#IOC z(ZJ8Y1SBFmFD>JW4X>*x92`!|ZWiOQ)xGwkbWfQ9frzqNf3} z?byiH!u{$>4^FPGD;1B*5A>To!QT$DP@U0rlhB<(Q8gr&KkR!`D4jq>y-iW9c)>Rm z0#|-I{EUakrVF2DIF&Y=jlyF+z6oR<{bVcIkc+|BMx=x{!5L06%E-YxZ>Q^QOuqjd^ll#z2m~z154RQTiK=K*wb6kZPxBqf7B<89FIlZp&|4dk!GxE z^|hL&JzRoptD#MBO2SiJjxYT=;-N2y+4P`GTN#S?0i#>MEzaUp@?ODp&$7;Ja;7VR zK({YPb)Gbw)zG%ZSsJ$J&xIw;kU>pqq2 zaouP1oqvs24~EI%Te zik7d8hV3~7(=Q$!URpe=)%@waLdM5K)QO4Emm2<5tWcn9Q z0nvGsh!t66emRx6Y>FtR@+YGIc?Q**FM{nX+FA-V!xMJ{fWa&tE;Ihj;VV+-CbCRy zpQeneBEEy?9Exzi1NEyKycmi!+aFQvFIN4MO;`~Y%g&Rj^qsG) zbnVagkH5j;C@%6P3LBJ(xqmxP1LWwFQ-i1QOpfcKV#f{vxE5>jlI!pB^F`v*_zYXq&817OQ;Id zG{2HP6y{404lI-xOBIuw^)%=aBqicil_F(&Mi`Z?n$d)KaEZrDw!6P971`uBR+l<^ z%b$c)Z~9BNMNyh9;eM;R-d`3rB+!zR!EjXI#%`rZ(d5&|@Q*FfHw~%x%mpzgG$fBG?cWj^NNd zGGM$YNzt4Y7%u}?WpzOuUT*?p?WCrgA5s51BzkfNGU0!muiSB3AWI-Kk2PbvZ@(a( z%I^|dLy|QlRNf6=T3@qIb0p)XF`ZVXMUAG0U#~yS^Oehb!VwcGTOh=>kY-aVEHSQj zA7_`;52s;aBk@jCk|Cv(%*Q(tV}IBNb4g!X>&!(_M%db$xR(2iY{h?#p=3!}OQ1*-wqis_`KZi{Nek$#kgfA2C59Gf6QAVur08U4O4dCe z#Uca=9OKBuhF{JiL?^Ieu3MM8qXOo>R^`B6ua`A!>MCV;r1(QMQnu*iJ>D3I*3uxj zyV24%PASI{wf zlUJ_v9(B^UkXI$~b8;(PR_Aw-2d z1Wy9%!f-thmeA8Qcx;rhIH7B#u~ZD_ydc}H%OA6tTEC@W>Wj5NHN}jSF)v-|TtHbV zi1sPOwt~JmW|r_X(}0OBgu>UQjb*30GicFu$yPHoE3$QrZb&QoG7XM+#Hl8fnFDEb z%Y*^13ieB#1VZaO5RFnfYNS1g?%_-jOh0bc*s35N=tvOlP#{7>go%x%q&!Tdp=v4e zH~bg?{v&k;jJ?ac%sV=YB4hkkF}xghuM`SH2Pa)PhZ%-)W+JjcW1FhyVO5 zejct+;@7Za@E*%dZd!koU(Ef(RDm$-k`Jsd>_ZG|lUd{8GVifYG5>^nW)OBOFg5K3 z#`2im#365=p5cUdlailW;H*>JU*gv6)f`Vc)if55{@(QqO<=7eNj%xPSjOX^U;@i9 z6X&berzs+C4TZ1A@@hy?9u?Jw(yvDGaF#5$`RPA2;P^mg6rz)qec8V8R|(%6D2o5B z?NKv#wl{Y6RQ%@A8Glpi{$2d1Ui^Yp#u~}3PmQf8=$!1JYqq!1t#H+@($!8auIaSD z*tkLfT*EDv6OkaJ5R2^Ngg87zAxi0q?2|?a%J5n8c)LB2Xqd5B&T!v&Z=Z19@LHC9 z{JFo^1ah+SlM^Y8Jf2SrS1+u`u~DmfG{sM#S*cvhE07(QK+k+{vioZa+o5iYzG_FK zB4GPu3c@4aD9XnBu@?GU;POwtq_F%<3tEUu>Eg*^z3m1U_C-DYZ?5(7Jilc7)4w>c zP18H2d2YendDK{`3-ET5eszY8UW*^v@^l=mXO}%q#ZmRV+BUfhKVfuKOI%spyogem z>FF(OxOrD9wIwz>+U~0?itQH9&7|I1sqfgDlR=>&LWwO?JWe`dwih0!j|9Bgcpb3S zMV_FIe3c3ZG{9rXD?4MZQJui=X{xHCxoI#l+Y4=it>I2v>{)iI)w|rT|8TLJEpT^MMaJ0O)AFZ&60ka$ zH_3N+%;3ms(4)bEqy?1&vzay^b^~96+o+^AE~Z=!egYxnC5Oh|n~B)4nFe$Z^QD40 zBKZp7!R#`{ItB&C?ql(Oz)&P7RLx$j15d;3a-FXJIubA&N}eAuNAz9qjv+*7ZTxCV zsrS!3Z%=D%79L3V#L0-%o||4{fZ0r1T?o#e(s^N9eV&O_PSMVe8`n*-SnKv_XuVjk z%K7>CPJ^1=hjr^}qn+>K+%`^y!!mfulKr5_cLI8T+W7TSo6;4Q#;!~)**0FMd760I ziJ(@s#2ofd4h;LKT+b`TAG{SkH6YxEsI<_fyzoA_=}&>v58-b-Caj%Ye- zugsCvzhu?rzRx&=w21`SEy% z%A$wIOrfz%rXVCuO_&vw2hXNSS_Vv8)L8YK*Wz%7Dd3+X2uu~M~f;V6pK7q zk6CbGnU_fk68D*@1;YHq|G=$AF4K$d=ORf-kkm49;Q8Ic^=yFrurZJ=C;G9bP^y;p zV&iHyFrychWbI@Q@;){tnyH%bV&x9b=tTEknA7zz51(kfpgfhG?#Aq_@BbGR8r;*Xg1jRCcsQqmJTT|J*L2fd~4@o^RL#62jEN!2e5CqD!F)veO8w#2`q2^c+IU)w-k$bHtFJ#P*}CI@JjOn@pFoNzeF|yqc~rmu z2aTE4GfqBRGzjbRd)*Hq^xxvHv!|%>_q0XA+Wvcj|8Et}X&p!{G)XkSM(-{96KW{P zAR|5`>IEA#8zoy{`K2@qn4>;cC@9NQBP zyFcH{Plq{Bd#^YGmQ!QSQ^|d*hg74vLI{3~xdRCPejY`fha_Re&hflWIIodBOL(uD zyc2k@esRWzAz8idsbyNd?ulg^h;I8i+$vW}O^1e~RyeQCJa@Qr4y$D0Q5=^n;c19& zn>lZY?pZHF$46pKLZ?S&&0NPvYRz1y$97@Ewo_S7dGoLyljmmP9j14TlC=qU2w#Ue zM2HWoIYoxob@5&(X9Z{%h@eHVvlnn#aBd5?=2viXHZYzKSdCiSzfW}5Kdyl&%kwLX z%T29S6$7jj&!89(A7CczPtUCx_2+dq7M2ef;a|Oji)Fo5W^7?v=yLH-ZO>1&c(v!k zlRtOwYBVZ^l}u*OXN-)BcX~^Pcktm{Twx|`wdR|=RjnmeExpeQlx(_}BN-A%JDJ`h zT3zEzF8XS?IRM843N8dtGZ$c*O4qs4QwR?a5b{3{zU1oirN@hD+K0Wt)F_O`tMNq7 zC1|J{yZIn$Ng!%flq8BMEe1*a9bFYm@n&CwLUyjDi^g^pD%D~yG~FOq0i!hJ36&<& zF=rw#B{(!3%SzNA*{$Wr74qzAVG#C?gIzOJ5Gu$*>0t{Y3v^a4MFsjEw;|Yc@knGJk&eX@w)MpR>u=HIuDvdI*RAK4L z8z3$o%9;vJ@mg9yrl+c=vP&}(mD`%g7q5U=S9SDMTqST65IipX;U^ZiywKdxIoMnB zM-gLn>@=GY<9B2lmT2ApgA%rA9^X{sWP71pNU@~&o3+=daUQq#7}K1$$<6t3x_-8> zzh#}@@_9+D0bHIhG#$cUFrH0H%*%j$VcmsY3O@hL4?BJSwc-Pie8_m@(#{N)u(BO96n2BO=a&nvDGzd)P4Km8)~OK4t4kOUPXX<1 zHm-_M{%!%YklSSudIQk6b16%^`Lb;tNjP=L4zJ&59SyZFS!(Pp)(`8d^0N3maNAegvAbVXD8g@6P>!BxA3EAFmp!AgNHz!;19DjZ{<9$(3Dm z)zOt-bJf`ue-kA+oX!hnwHm>t>28ja;f|B_+Qw$!v~}f`Z-5+bDrmeXlt0joBf7e@ zwYB{Btlgi12!cwb3gsV49FqO#Pw=i8A?2r6ki5Q}SN{Sq+dqxjjGT3fR9_f1vTXZ;j)V5+UmbMyU{Chnbr zYgjNV8%&V3A0^lJQ{2MC^*r`#Vg>nDV4Wg#69t|glY71EWFE%(_F(ETR6qw5wq)~& zVuj#k*$HO_p=JEUz#EY*5NJ(O)Pz7~z!t*VqVtqniVOhUu|*}1;LD|m{qwNAU=(U> z*Reh@=fdOFj6IJtEMQXT27c`3R0$Ova%GC*xL+#8sO59_BF@b8@z-Y5?k&pKStjn3 zhk({VeIredxPFf=7f2HX7Y;b~L1il9Rv9a-a~DU}{z(XSh#EVH(vbll4l-Xydf002 zzL7?o03I{C)rGvyq?Q$)L@SXkb4n(VGnyiEtPr+|kB!IVsEW&7h`T_^+a zGLkkWI8Iq2^+=$JT@P-&+MvZ{4o-ezPGaQJExgjLErWK?uJlQ{$!Wi{Lx@PiOT(_S zoiVB}iXdL>F6y|n$od?BQ%&%aOY{|7^eKka3Ef1V*Q8($Vu`;r#}`YoKQGl+EZc|d zuLs4IKlNF%LiLK>?Ys8S2B2g({n|h$7$QGt$((GWA5qAhaWhSwN=zeK{>W>_UWNOy zovra(S&q8(0088k_IZ17l0e&1&;~MF4!@7czD8ua=Wc1g`wt03o&067*d`$Tm8npddvU%u;wyC zFt0dcp0G^-Ina4%2Y3doxMfDOab#{@fgQO=-Fb5=aMuR)`!O0RMKeRU zQ~#EgsNdR%)+?J8y$E%@Fd5SWX=NxT>r)Qc3kglts>Dg1oN`Jx@xCN$5I4Xt^l)8^ zfag-&wEmfs(Q`EE+XOUxSDhk}*8@_mIoRqqrU$uGGwS9DS`11E>ce;Ivpd{Z8R($E zX;Rube*A=X)N1&0#rdIN+`FF5c9v5p%ujM;I)}{c&v4jQ`^T<%rNF2VP- zgjGzHXg6WjmoX4ekqwWm4OP2RhU^7Yjac}>+{733ca%v)vF|pKxzweTr4v{Qa;mXb z?Lyen9w!DaO2l5vy9t`Lh}Qr>l};6Z|AH;WkJz3n+zm30xw{c{2%ZhW13CwpCSR+} z&`mIt{OD*rnzT5Xyx1!Q$Tl$H#^;WrkUcS#Z+z=za&Y@(N7+A(g)S(l?2@HK-^xIjaUR zt_JFbc(>l21u{VFLVgy>pEt?ZMf4QtNRKLqD*pzv-EEeEU0INa&#;ur2tSV-5sf^| z?a`YA=?Y)m0cBAI%Li75umJKu#>n&zk=jBr2dR`jtctJ{s7V4B#7WFSEP!KCrIRQV zmbGHV{8K8yCzcT|_()1JYp&6K3Hs&!YC%T%Aq`fQW|~a=96ik!lawUTz@hINbJKDn zwq+dY4~&DwlIh3}w+8IWr#dpwn}#>w4a>~Tu)*XO*#Vo4^Ggi%E4Wgu+h-5y8!bR}TSp(smD_St~f;@9EUNhZzb6zGvRCcrGYb!bKx z&dKN?%T)Ri5+Q2kCTonMjjGW$!?B8Z%3AQDwk0=AS$oBh4#%GgfcUhm>3F~)9S*l; zE2^xCt5n|DhPv|T9?9O1wRMrb@?eK%WpTeE{goA3eHeG^Lb40VB*v{e0PKYhJ56lN zKf)=DCauMI%p`_*KP;?rqbp=@NW3S!k0kW7#{_yczh=Ovnz(f>i?0CVryGsA3HR#| z+@+GPQhHkG%Z8Nd5J(0%mtj>O-tU+cV2&t+AEErcY4WtgdOGCC^E&n9_(1K0#Qu1@ z)F#B)2p-I*w7|8X-O9G|peE42zeV8&O?16Zs9!q4d@K8$Cw<3dA|@A^ai>9 z<%a;m2k}51U>PW&=@Ka`)~cslx=*YhV^^El5w|H3`a-Q*! z$2ydgCgvTF=z?&{*GJNaQZGoc2z;)bQbu5&-f|*Z>?QD^lOJiux^xzwpAsShABOJ$ zyNO9_I|%1ph227m)-qnpHu#Sv?O`&Dm5W4hJ%$*slZS4^Fg!RQ4Ry-~=0O3%2ic!3OBz@j z*+>QdfHk*A`d8~{h2Y253h0P;PmW5_0LnTrg%! zjLtN$R5~qI(!C~{0+D>lAR6Zij$EJqO)9Ytf>DDtLdhaONn)8wWSL58*-C8LO8UDdS$H1aT`fNchdWNNvMW%{7y({OI9piu?*Yn4e! zr{dF5-%^Gqy4wAmBOy5EPQi_9BoRar0Qp=$%tLqPRjiv{8gl9LL9;~qNN5H-sq*C# z>X5Pq#_k*2V5PedrG0>;ed17nx&zAhk#Xn=3a5t-lEBko(-?DvKnP1nnvw%G!MBeC zRDmt?sulRe8;2KLB6uW=O{xVuehH3Fm zzfjvHhG~QJ%65(g;|=pXhCx4?5mXC35^*8yj%P!%jg2V*EnO>*mJ1SE z8(32A>7+T))G5-%cYZx`1JrD=sIeg{n@#tE zxVY%yM3#hzHGw+!bceSHJmzdE`wT>e{Ye$F>$^s)f*tfk8tK}@os^*@7?%EkVzDrp zCS7aH-4mPsfRM7^xt1x|xBX81_xM*GnqZ0E9I8-i00X!IxDUy#v{fdZKtA} zKMxVKhv2!s@0aK%^qe5_YpLj$?P)IJM-=f-Y_pn>DfPH^oCnuD2QXjMTi{)H&|XNp zC($q9KNS3Mzen@m*fw${-zKg6!LMqA{7@e{^L9W#p>G)j{3BW%^4_{VGW|lXYxngJ zUqOAM-jH%T1W@e%)MG*L0K2eQG2YJiae@k9*sbrQG8_0%zzm)2B~uPyx_DPmu1Xh8 zPUilYs-1v-QYOd^9nB2;)O+bj8PB!8d(J{g>y3vw^z;PjZ5r>qW}67_;>0vGp6eaS z^A868A_)FqB^VJj>hm88_zJ1s*Q^No=4R8N`d*q}CofM7cPB?#W<04jJ35i*(M3AW zhlC!pe{^cCy*QIR}?^q=-}NaKy}y5DRiA)e5UjipSnD z<%F{7(-v^+L_`*b!+G{Bt%;(K>Ipbcav`W_k^|o_2n=t0;`^R28tLVBJw%_}2>kVy ztj2?`3Nl@mGJuC)DUGD0G*Z$f0)j|)BZ7p0N=P?|grvd0!QXRc9M0!=eRExV7Hc!C`+e75 zd(9qZujjE6p+Eiprns-RxEgcwRS43ibITc6iM!m>oRfppky80*?RgNlDKe1S((yQ~kq27lr&u&Zo`rUq>zODG;y~BD1{_DN(c^21a zuRUN+ZCX0vGfMN8I&{14C5j{VJRm9<5J{bxkJ)m#;U$VKMnyT?Z7;T)5GBV#jUWDF zFpQ(1m5^*^a3t(l@dn-NLZX?G9{V*MoGsRcA=Ny>aVyf5;n^8o`z@P^_f~J5ulX@g zWkwatT`P!;{2~0PJK)HB9BbL+IDz7bX1G7t=t^s8@67wot$V0c1c|K$O0S9x!g}7z z37WK76}i z^)b)qeJccG#dhU{v-r@H;JC5shv>8BoRb_ip>b6EMdQF@!JFPFSz`VgZt)G7!x9#t zW6;aWg6rNHk%#faqAQyH+-s<^=ulDSfV8Dl-ELmFN9`I!SMX>G-mN}$;7*@gD{|=y za*%35C+DGHeo!JG|3ifI_1B0Fl_^uL9O(vIs{z`kD`l-sA*4oa{0BU^?+qm*O6j{? z3FkdSwsA%8Pcu-jPz<_{-_go!RFTQ-mC!*^MR}6#Edi;(H^(Ds4d>3X0DohP{!rCI z;J`xOQV_UVN27ah%B6NYJi>I5a>CxtgW`H*p?@R>2}Tc*)(_dOd4K$yF#+k*1jj9L zWA6zp==Rq$2X%}fFpUFAt0k{jJV%|5h78;bQcO}6i#*b-lA$&DZ^dM&nkDcaw1^%N z?k*@TY_Tb#q+tuId`)><31dP1a(hsBygCUot--m1l^G6Z0~J+dSY_`k9g2leFYoM$ z0slODDdnj)BDvL(`m4j57G?C9#C3(pthg`sT@ z9XWju3U|o@zy86r_`-Ti$RKcwzH>m=`gS}<9f3196djr%=FhZ-wO`Kz5lFr!Fz+X` zEZgqc)w2|3BwQj@UQ-7ya4)E-)A+#?u#j%~>a)Z)OBH=cLq zz7W)1RxjuUs!|(I6R%XE(ed)RF4UdsWR8>lPbCfh+>Aw}0*pmcH4_ai6A~GP6MP#C z#YRMJ!=%$s9MnA2~C%U9&5kqmmcsvu)gfOOTIl3RxiozHJNL~gz_2uaOOrk!Qx+7)2*XD%h48xkOeS$L`q=@0 zkcPBqW(9pL*frM$$9R|WA)QR_MQR}ib|$Gdy)AD#oi-B7Xp{PS6^m?zl(>xqrUJ3L~~AC(WSSj+On9)y~07oZ(WysM73rcdL?6;w{P3u$zat zTGcUkUx(-FW_e&&el{`J=Xy48sA0;3>j%QjaG{??A3Gy9C! z#?^_IWqwgd?Vb#xO@*(ZOJ&~|x#I8(_A(DJsva!ppm`I%d&7U5tCvOBD2(qV<-6CB zyxP-L>*g4JCkB==Q_2%7^(H?AhWb6&Dpx;^6k=E=G(GXK&uT1~lKHyAW@XeExBuQX z2en0nqG4}_5_ihMLtyDEV5Ye=m$lrEy5~j3b!cQN*75jRur+?}%?9t$qRydQrM_0v zOY_FAeteEC6@vw@Tj`fI=&z`*g~(pyx@qFV_Tn3->2$*05`&SJr=v8Qtk3>glMLRVGM!gTMfmxHDGGsb_GU#xu2GvRObNDxKosZ?y_t9EU zxk3$;$#XXu*ZA_HnRyd`JmtizZk)z+F{^d9?4&onX2@SLcbpWKh+pESrQF$+MI04b z=+-$H*4?4i;Aq)7Z*t9$uVQYSo4AxpZ#yt4?7I|OI;rM%N*1vi@WM}nVFkbo?JPSr zfu_VO=B&7hVWfK75lLa>!P=sb{JBTK>xnhD^RtKtfY9DqC=<8{Oh9IkhX?R zB@OXsf?M*qSP!9{Ut7L54G@l8Gn}_w_l`VpdjwfqIel`A5T2U1{MMZKF_FO1C2;Jc z>x1T#gQm})mPVVYJ+UR|`}d%XcJJ~Wm}s}ge|DlqsVJ+1cW;W(a^bfCKnCh5AF zldG34H?@(vI1Q(r%!DB6$MpP+nv%rgpk*(hCUvD#B~qr$Wv zZ_`4Mkj#XSAPS>vWlU;pDIzc%HB=I;bG@q(yR&v6)aAvfzIg}9P$lOROh;YeX1YlSHm841r#d@cxp}W z^H^e+@l`p@=At}_&}6yGKp4WTFIWjGn02;}H*WRClKG1MjGr=Ol3%!y_Xf?&0tGT5 zgXbSw^dQ{B^L3ZD?VX{eL-x5w!bLouvujYOGxYk4+&Yj2RDY_Uy+v0r^~dJ=y!H16 zGX~r(vIQ63Qdz4ticQJpPoq0yn(=<|X@bKkbzQO}BqAm`8!SrZx`IpMzI|A+!6;H3 zxAyw(l2Jddl#k!F7J0e%Y~lWehrtO(EyTv5a`Y>}WY4+M)GpRq@f$Wv``C+rXNPAc~QlO|3^%Hr<|*)}Xbr5H&v!-rI5X z_B6o*LHINU9WTJOcVTu9)*rFN?uouDh!ua89oP9~{4e_*LrhesnZ*;)%k9#v;N@$c zi-mle`&w3>7o9M8^&WH0C+Uk-b2p}^YS2Hbv6L3WH9uGO!xc_R&}R3 zYQO<@Y@caVPm}e&on+O~#vKWaQI^NTdWCZzn0VW1KUqDqy`}Z6g8u$Zyx#EDWQxuM zF*&8C%}IWvDF$q6IUkrptL$YlTaV@E-J5q)71Rias=+d11vgA0DI}p-CxQ))$#CX;hqtF-PHXgzz&d5clUuyfl-EU}C)k>jXA&zY36pQ`qrd8GDm%~ivl zR4sna4y~Q;jgslK${SeYsvCKM23?Pg(qHVEv+lAdu9d(>^ZP55`NmUK<9INYJ$J1} zoK=~cJt^#j%f4BO5b$0|bljb4_5PU1J=H_1-zs>!M^G@@p)AZ4FZ;a*Pc)gPJVj%P zto5)w^Bs8?U3sUMF`LtumAG{AX4isy2B^y^6dr?gk4eL69gBOQg~RNlDdqxi91A7!EtCJx z9!A}r`INg&V%6}GZ_1oxYR<}yFWJqoGdP=fx*&BY!WrdAHT!#9k1Mw3p;rE9 zs|CR{EcXkcU64bPdrcm1s)Lt22j?a{$&7Z{H(v^|)r^j{!1~dqaGl)5Q(Kk?zqq3{ z`AS^5bVw)s#YFhaB@}(dnqE@RL14bNG3aypZ+pBVewUPalwc-e(|xE*Bvc>QvFzDyc#!+$yG2j-3%Qzb&E>XE z@EtxU^Wq}cXJ00DKb+jOd?VJc@}9vfl0T!b&?MDPG}xl|K+}@vQP1TcqCqEht1f!D z3FWkWIf|>x5uRpm;=`w~_Nrfc6iSZmZ|lA4<-#~(_vaY7c2r)IH_H1U#r0ig?1AU) z`lxZLY*(tK?fMvpL(BwQGaRwk9NteH4jHO9SY;<5lW&*ZRzwF-m(iI{!j-=zCVeS| zf=apdrlIx?oglYV@)Nx8-#NXH(|64HgxK5-t9sjSdnjcjROflUetU}&r`=1@V9~wA z-8RCs^mErj#yp)+dfXGmA1Sw@eJFie#)CyC#Z5k$HtmZWzw%M!%WxEv}j(D`o>KL|Mub?!sD_14QsC7nDbzc$suG@)!WognoqumcD4{fK% zji_z7;^wqgHgXchSsJ|(A|p_02clzQzP~$4ucR*AV5WK@KHR~@yS-k_Bz#v>z4NaV zl~(HF?+WM-9FCgD9zSt8@;)g*Y3(4Xy&gzpID513x;p11M5U}DALA^SvUo!;45x~R+N#_qN$GTR|1eQOwX3|$ab5ZSvGUee z0dzxE`=<9YjN0MXDCoRai0+vAV(_`C2YhZ8+ETz0%W7f1e3*-pp*2JFl<^SF8dD5R zOUG?G$l7*e6YAwnKOiOOHa%x&+l+-?(Hs(^9VI#hO5Dnk*zh$O3RE1z$@oCH z+u8q=upWAE$X{MdZjTYH}63b4oefJBfrc@MBb2+SOI#{I>zS z9u-5(>^a{1R0Twh?NbHU)@5Fp9f#k11Dm6P&0k?K4Uue?A&fjaY1K5u=kOt{n zGFBf-+;WYnAh=dTimBj?AlWW?33EE*7TSO-WZh;_{}EKFT1KKmi-8fh3=)>AYYN+peT z7VC)YNV#UgtAq}U4{I_>T+38DcT2Qv$~t>63(L)WR($K@qGY~pe=#TH3{K~qZwg3^ zO2oY*2O%gRy8ndRiR5*Mkmyu@P|vcL*p-moGIf1l4+rBeu9*wC?}}RO%32s;SJW7>O1yF-O~ESKmYjHaVkc!kl#P>iaWS{SKVBzx=h`j9cBw->oA!c?0a=F| z_lX6}qB)0hgDu~hvcEmzU)`Acsy*wb@w`6;+mOHiu|1)MzhL#&cPBR2L;m<(-Ohq2 zrQA0I@0ajLm!iu1V9B=WLg}-_k^F99@v0AAgwrxgO4pSxg=7F^h8OBX>PFo+a1q5C@2YUeGO z7*i;L0(%(zs}A4lSmX&ps~8Ba!imoDJ zIYQXKTK&C*4|_BQF>FGF)*XIp-Pzp9839o}d6kM3NT596?!gtfL{1Unpv%CYV}jO7 z7*&<9nOJo10157&`&hBUZNdHs%U;cIJ*} zJAU3d4d0QvS<$Xsc_UylmElIKnh~&8c)@U)?J%GZgcyhB9pEk_K=-#0<5c^X0brj# zXn^f25ZNE%_;+l`>Q5|fVeW5O5NHJ&q;v}T^`Q70O91R52NsDUVU2&LZw0eM=Lww%Q7`4FOVO`I|-q>^ap?{7*DV7iY^~H>SgP z@0_6irPJ;;5gR<~-k6&uNaSFE+=lVBycysS0AwZvvOdt^|B0+>Z2SMKf#JD{j%t{v z+~x6~T&>t*ByJtR73B;-Qv_tVvVcWLTnJnvz%lDTaW!0wZLFN#8I;ZMo7*5C;QA_% z6#Tdn-$YLQG=LdRqvCcTaX}z)R)hfdfl24T2;k4?Uq>H)NGAYj{9>roO8|=o3~Oct zGzjNEqqU7~ewl^Ace-}5{#E##^W%$Q7)EWUvWi_ZgTa zXyoVYvGnv@uo7=~iVy(44Gc3xunp0l!4PEdobwn0SRW(xT<{E&&*TrFt4)EfMjT#i z#D50!GMv-dZ8z2s&}~PV=b{(I9S7KfoJo;#<|6$s(C6e#^aBBG@A>3ha5%Y?4-b&@ zsZ=`zVO(bdH+%o-C~G=9TG?6XI2zjnt8I{jpwq_nJ{@Ymj`$1ioO6SC({v~21(10P za26xJU(f^g%YO(08EcY6fq-rMl5{Q>m#wbq9e@=Fu>ZVYoX+4^XwSnsI{va{fIpG5 z$Jr2Q)mZsRG-R`O27q$y^3l5p1T@Hqb*Q3M>M7kMxvdsxHc9^~cHM)so}J)0tXWs$Evko~LR z$xx9$kdaT9Hu?kv=m|6Oyo_w{1P`qcJqLf5`&&g7J~2;@4gvnE5pcr(yR!-6R~?>(EDi+EVlX*} z^_x@>Jh4Ig$uU*fKSW$(F=-{X9u7$g0Uk=XaMkDZI>n~^n zjP0FF{~K~P;eY-e^8bc(F?DwNFF5Mo8&E)J)nxM8hE6-=z(7EUe^2)R1Q)Wivv)Cc zF*OmfF?4n&Rk5^nurZagvom%2uL*kNe@v$+$;p5+A^9G(=;^dnxA^6X-sT62cdCO? z!GsisN#C5YFDBb6yEX3b+>?6TLcSIaj%nY5@;=6MJm{M-CuO|Et#E*G_SuC`A?Xmc zSQ93b1eYNN4ipg;I2FXWr3F8yFfB`!4sVH?t(~dzOAD7e zR2|DVO6TJfonsZv6RXrOURoE~J*-IrUYwF0#4GKMGvG`s_*C3i=`r;u@FeAPeS3%?H-~I-m*Jjgg zz|BnXox*)UdCcyr^g|T(lL)vDQ?u-GZQS3%O3z$Y<@ae)4I*Sl&uIX;)#-1x!s?3U zRPPw|R)w5X{Db#@dY;M%SSAFsCf4$=*Q-E)fLQ*s=k4u0ZS7s1|K)iXCrdkX4JShf z2UDkixm|fe9)t;%53N}kXeaJf*hfstVc)oviAnSa^c*2$GTd{)7|FBh3R%g#e-)FbOlLp9f4a zOePDO!*C)-)*Zu)zt!9fUnvy>_{`FIm9)27T{);jh$G#!_th2Eq&P@LN{ZD?LK@hR z-Jnb5Z+zD3f$Los+mz=Asiopmu*7Ks5;3;i^fGCb5T%%u=DMM*`@s-?C9UNZFLYK)C*j9kRVigXS(qdZ~8NiUVG^e`8{6t2PCoM?-IEX$#vF>!Z7+rO9r1 z-i;--!157Od&A3YoKpMcbSO1Ei1QyKIG&IQf%tj#fDlEP7-63ff!NV8{&zUoP9^p* za}ILG&CB`s*Y{1A#?6z8LibiTBF3;$7~~JWvPXl&SZcf_?&CAfeB**xY`iEJ+GXU0 zdesqTya`vE#e`+0+9Dx|A_SEYa)NflIz&CD!6+EGr@mfB0xyH#$;is$($JDvWMro! zCef+P%W>qBkH##+uL&Zfac04PR%4<44wb(pjeaqofs*Ij;{#JwgM5nH*l;{Q z-{QscGplBX5zvpdG#--b7$R1)AZwpRKFgMBEopu}? zpU5gG)S?W%w3ItojnJjqF_>;ODM-wu31K;%J7&(TDDnrRcNM;b47A8y67aCk8P>7>{XDYqk2p--5@$oV%CeelJ zWF;(<|5)5NtMu>tOmGhp!~oKFA`@3By+5Ntbs;<{clTv_LgqDsUSdeCz%CF~8@i`sDDP!?cg1l45?kkTL zbC*3lV$JzcX?9I(#=-ML2-;aPr9IL&@M)nA8@8aX8%1i+L*cn_0J}w%8$kkQB7e@E zkajW*$9Sy=JSyKgntnABaO*(Iz-;4bJ7cSfK+v{#5~V0Ny*O}IyKwE5NZ-s}Zq>|0 zuPxW^7e$)NxJYzXc)qx7$IXu)-9x!YC5GvbxN7V{udN!09MM8@97TG*;lPcv8PnaQZ29vt5Dh7}F8JZ`byr z#5bzuD%XCk*dCd6n({lMTL{BAQ8%0C?42iwW>H%NMkIRGHqBaiDCZT`>i{E=tp`ba5L+ve{ER~{{=1fO|8IbUd(t<@(v1XzxqD@c!z>(a?@q24{VU%AHhK?*7~h5frM_}mOqR*pmphCT;jt_U=yR-%n=2e zA|T*F#ug5> z?s+`}IwkdqYZF(-bPnLywbR&sYR#KnDbJR>h8A5MTS$v+&$oQp^5z~LYGIzLVtz@@=JhRA zVlhqeKV7c0su-;6MYTt7`kraoQ=7|D(eJGr_@dq$&|v`~pXjzTh4ocpaDm_C-=7MC z*U@?f;P!^3vajU}Hz|IQ6K!ZGq?E|Ki{f0uu)KmHH7LDg-T1qPS@{&D4s5l-YAMLkDVyQ&eyr9yiOQZ-Ku>mG=)kJ@u5cQT$Q`dNDS4^vVAf% zhDr~yp-O6fmAm#x4ppDa0qyi7k#a(7BX{DkCKzU&cs?IZj5&}*K3`27Tch^0^y@1T zR-#b9X=GOGqET3dWz2*RV8xEx45Zh z;{uPBhHrBYyy#F3k^^X*it$0oH7GWlM4 zSvSMpu&*%=iLy)f3~`J1lmhTE4s9PTJs?Z1Jv8E9z}~>jtzK2j-gQ_12-ki3!?J!7 zHGM{eV23)U2X^kN!|0+VWs&Akogu(PQj>GcES;RCK=ZAst)!>t!Y^a0L*c5UGG12$L+1uT->VNT~^!lP$5~ zvur(&;Ga$*zqjKNFne5gyml}o|D~x=$u^QCF7tB+cOVlmBNgvjcp$!6wHZ>d3O73I zeQIDB`&i52S3T6!%JPwjr=?;7b0|H7{VU0P%zpS$w9;-UM8vXI9j`IHFtA4ffMQsO z+&B}7wJ{XpAY>vmf6adB5$(G)JR0S6$lcZM^rIO%BH}$;a~5YYuzQ!fFL2jOh;7x- z<(~9$Tc2dDZ}37LW9vTL(8{Z-kfGnirh-r{P!+ZT>&S>$?+AvROAwPDBXk0904uf} zOECp_2`hf7!4qO}mcFk)gtrTd?X$D>b3Xe8@XGXFozT`^yRsf{d0= z58V^5BoG?UZ19rl((Y_zP^odvv4iIz&uBJtZoyimQKm%jinSWOE9_#MejxQ}w>Lw| zJIZpC!e&{8T_MbZf+S_W1I~O6`N0JzB3Nq4ao?k1Abm!U>v~hF;5Y4AdLMM_0yo#S z*(n~vdaFd9!d)B8Cvky_sBozXF8#RDN+&l)nC!Lh^x{}Ou{Jwe5doY48BP9DoicChmN~o9 zuZoSP%c(UD@bZM%+d4QpYBzvQRH{@dw+LEusfo0XNwFPFIHN5~(g$=)n>Ry{-J(k2 z{mGr1+xQz0GSYY*{ZExDMA_Yq6Yp$!ALcw-&sE@iGNH+lVBD?!HA3;b-S`6$r{r2# zt{Ta>xYCuKBq#m5nu6^pLjDlZJVW3!scg3SL}K-{0`^@z(Hu;TBabAPeYknGJz~8m zE9u>ns5{<*b>#jV&b*>PBHVpSRs55rrgUo>I|)nHUG3N>na!)9Rl<0VaCpf2C3)Z% zq!!D&3%2Y2-FfV|UqzWd-=9P_c-4*)*1U6>pV+Qg)cB&nXDAi{fkZZ_c!FY0%NW&k zWlvvI$JDtziYTt&ya{DI`C^65m15Q!c*2z0l}qvtE3aELK1ylcC+q#6JayO!EM$$M z_{4G6Aq>hmidIqLMtS|lz;PDvU~h|haXU}-$m7Vv5b5&mkQI)^?B<_rzjJVjIpVnQ zc-j(9h490K*M@$FZrWLK!mglrA{|e=ioP{Dfcy1vHFY2$o@)?e(BZ}cHq|UkK{=Gi zqtsmr^U8pb2OWPT#NlQcVa*2dJrqjGn?1+TRn*K zPxCK z<6UyWMS1Rlw(NL{U*(EV9$wC%w|y?@DN~I<4^h$*5wV6|Y3%LQI#tGuXg2X#WRtN% z^s{BiU^upCyvMA-+Ni09PpL=pjItatq>!ViUD5Nm?~INjUNs3cbO}=1ptN_O=>2ap ziJU?2_6>0QyN~t@;V4vqC}RqeNqU>mZ#bRT$1aGvA)pfEo1+C54{avw{ps_1qWjjB z6m+9kC@WRO31nZ`NXaZLU)TvZjFuO>RZL_vANOs+>d$F$oWgLX#t-DFfo)EZkK5Sw zG(gb-^R@2OekXnoZyKKIa-h6fgE?QioxhP&j})o=DGzS)bn*D-Nm3J>b`;7D^W5JTnFDk4c~yK`M^xrY@=9CS{7)ml_Gkv8xU2)# zIl~F1W!~WT_xVm4MO1vzDWkG+l(Jx*r?gytW80n^Ba6M}HUGvmxE|WHMr8YNka^>? zn>*T*AFC%6h0!A#(>#R1DxS``687?GN+GyeXJwt6A2285=ZwBJA-T+p=22xHP(9JC4|-F4iy`eEV_|T&?%LM2&&N zTM!rcNf#@44DZy`V5gX$kVW=wC=$S7~7B zBp46#++fXuKk4>spy7>@glx|3F-4c?(!Cab2hOM01F50c7er>%M|{fnW4rj;P6urg za5Xg82p@ zb=p+*gsEakQ{YM@mv#%5jC=3DDTV*gt28D33BN&sfcpQ6l%)Sj^$>P4HMAD7w{x+y zb2a^!K$WsK1FM8NocGZDhr6N-&~hem)x6xDEPY88SVop=u#OPwXDe5_4@>k+6G28# z`YK6A_Io!_w7>Zkb`Tun6P8|AaVDd@yh4*Z!+E;%gzx6Vd)rz5{dglvMZoM8`Ng<|pb_LW2-p`%kP=7$0)h!OC@?*yhVYn>b~i$9n|wD0 zU~&=#P)1Fx%O{vJm7&qxXz~f!2~Znp@ET*bKtqb=H|SEDSvoI6Omfo5vb@B|mPM zM=x?`Fw1-zs!H7{$q0S4=6tbdVm5Q}o#RCkNRBd(D#34kY(TT`GtL)m*JNsZw-SLs z!rp<~sq#-`i4|wzo68s+M{6Z07BSA4T&!D_v+C)M&x6;Q#OHyxF2itwGlz1)WHDut zF}Sryg?3?^XrE-Q3fgKnHQ9QH3eJ4MVF`PzS~8M;Nv6wD691#c5D%yMcQ-KuG;KS}46 z%ROcK>{k{nvuU;%bK=gdsg}bmQ>5A@Mj)^(A(W2OQ$w<}dy(X3^Fy-j=}});EVN7m z-w|AC=?`3qmgp=~%0~1Q$HE}AgvUN!RYb?xJqFY6OttKcKdyLaWzMW=06p5@`P57A z9qi)bh;@1r!*ZKPQ=3QCn@4!G=kn+-7$t@rW`>AoD_?_Y4sR&*JAuCrU}d^*f8Cpo zy8HV;yxkwtB-}u~$=;`oX%OW-oAY}iTHg8s;?jKGadzgh)xQKQiAu!pgW=1zePyg@ zZHiI3{UCGLWRD&4J$xY(u!mP)PO5c}_9~q5=g``8eqo)hrbTa7?0gqU`W{NJ`}f&+ zQ=Wm5DL`-H}uGo}22%RUIrE3Ja%rNyX^e7JCcwtT$y?!HVtno^PWVPJ`K8aRgCadK-#3S=z9+v%lui5e}1E| z3_S4$BLEOF1$^Ce-+hpq+ue1^`RiX#+j^WT7e?r=Zhc~7$E+u-NOZ=AM*Lf}DC5RMqz)Ee&mZ?Y+;$5>y$U%@-$ zui#Dhp909=*x~HrYYJydX8Q|#TG}nsS{SVTRSx?h_gVJ{T$!qDT=I|;_-6;E^;3d(&{a%WS1AFE1*PiebDPLePsy_BA7w0Bzjixt+K3kj?w{=j4Qe^Y6|Q zu>;=={~cI;7Y7+^5{$o^El(Y@FvgWco9Oz$Eu7B+v}?gQh56WuD51v-T?%Xt6A2+X$R6no0DC5>AsNnA zwo%uwsvB3vH5qqCYAqApk~xozn&pdmwH=q$H^{PpKWhzZihN0Z4)&Ha);CJieGc7|C-h5!y8A(9Y^5lxGle#hrO_Z zbC^+_3P>wPykt&VE}RC(Ryu%DMTCD`>$FzdaP^F7SO!HvMsKeV_A`n(v%#@oInN!4 z%KT1f-BrF$`iwsWbwi--(s=n()N0*cKZ$6WcBMT|XR|>8{bA|0`wjj-d0&pOLL>dl z`#;KsB>yko|G5V6RosyNTN~s%v$ee%TJ9h$gwhv$0FGo36QX=qJo9dcXPd~RU8_1Z zeE;}5(KmX>;`fPv1%PqFgJ`15_5h+ZsUa);odjf{tacik7|m!9;YqC6D^i0UD%Z{ ze^2F|CH+BM!sLn>Elar{Q8)geR;L5^{!4nl)?eDQoK&^C@ca5|k;bYP6JLz&O;!zZ zMw`z4??)WxKMz%B$u@3Te z-g0){{_vl;`@Kw75-8;LMcrv0XAyv-E>f0hFsk=)f*+vCDl)1FH3pI~ACIR~7ERd?f7lP4sqSFDS1KToO9*n z=3B@&q_^ZINb*Bx%7WbZJYw1mI$;Nh&a{LiVLg2m+o^k~NewdqC zi_h$Q%WP7pC~CG{mVTpv;W%0ny2Y&pp`{p%ONz%@%#k#=V;T9RH0eQu{;(h^)VU(R z5oL$SFrTDW`=di|P)kQ4c`3t=CD*LeFJ-*S?o7Cb-rFDIXv~NtM-os5%flU}jAFUM z(=iDOtLIRgEAP}7zsr;<%Aq8@M4&urbe3UYR#T;&C6gsys^32N^Ku36l>JFQbW9TS zR;OWtHUl?jT#wi)691Dnjh2mH3Ba45;o6o1YDD?oFgWznUNSwD`#Fe<2OhB#SAt)# zC;SGP*yz!@Gp0K$7`M)(wj|UJb!X><9-O*jHtQoa$``8PM#T1Ki=QHw`rQh_Qduc4 z7${?4g2WuPl|;XC^f6^II$V(iQFDVQ<%r@%ye*1zY!H~(DA9uh?nB|L+NjX@i={!( zV((0ME|LfoGMON#c_tdC4Nn88iXAoh*}fg($lmo`7o8nQtW=`wse(NEc>QmcmV7iX zL_=C)%#j0mgC=r(i(s_I;b-fSVznG!%`ftl!aV1~8Iwi)vz0>-ueO9CN)5uUA23H4 z#Y|B3dHrjw(v9JZlZ0fS+Y7JEJqS#`iV*lr@L4tIB`BYV)L%O`-SES|X6e3DTPa zhT2}^v8`%;5cQu98)t^VGifsEClPCN|YCsUqq$ma(pl zT8Sc<&?mXA-w|i9_4%_g*45najK;^InOmyr@%(k|DdRDc$9I$eWalM6*Z2iFgTi3y zfAE&7^263{ts|x2?H;p~3jA?tQ4m;2F6CjCRc)+DTO|mb_1+K0Vs=pC>vifOY zg5GtWPC6iKh$7Rc@%7gJ=QO^0;}`?Q2%|i;(im?vs%6OYaALlOh;-MZA`&tjh64 z+z|R?eM{f;3Ov6>8pmIIohRcAA<_qYd@ecIA3eASt|!@)<~!jIO0bRB1Di{_q$;f6 zMQW6d)u>!YrFl$q^0Ii{BMAZdwETYO(Y^lRxbgst(FK2fhpU_ajIv?sq-WTy2bd!3 zR#;)oHHPy%KJ)?KfXj-x&sPSFa7MCyr;jL3Xdu-I%tcOp%|CDtH$;Ac{X1S(b&$&& z?|tYe{7p!re|M)$|0!PnyIqC!zb^m%{a@Qul?nNNK~z4Hb1+fG1CnmB%6lkv4m(D> zaB^}{bhgVdW??ByDXi%0Pcn?*!4QI739K6+WUxS{smU|0m+iK=NguziUxdN5%D6nZ z9k|}O(6PR;pa?++@duP3p%&?z$3>cgw2`Fjn8IVK5rzy}w?P$JwdpMck}6}V%=Wwr z5S|)M+FV!6-g_Rg?I!8dA82EYc`se5D7nM*es z_8Tz`aMz-1fLB1EJ!~r}h{QuK<_DRwuA6esuwo|e!1G{tS*(%H)2fsnFVy+K{YC&? zEnbd*4WDNPd5SR$twqNfOsy6AgsUY@=v2Z0r1#`!(W0ZdtJjUz50d5U+k3wvDv*Lt z|GiHIf&r8lCr#Y6b^$c(J+Mkg_8L|h=*(3E=Y@)6q)97A`2@jmdJ+q|Gabp_a;fI)(q0efw!WXOM zKgm;}pR%Bkb$~x0{>`tMR-jyKMF`{9UtTr;a!mN2`E@aMGBY&(S4MP=?~)&2L=Bm_ zLKG51r4)l2?1upLFfyVQqmDG7G;yDoxfmTBbwt|7^MKM13P=bD6W#<19`xtcJV}~y zcl~qs_8!U}TZdFz;B%7OrwJa~F^D!q=|Nes&c8O4@ntn1Er_@xhu z?2$su;8!IJ|MXK3`7F309Xt3>b$6-{>m2PfIHNSnEDQVdPtcEF`J>N9CnwZ-<&&Q3 z0TcOtPo>Nr=hS(3ZRHbN;5rvj1720k@^V_d%e=lFD>yc;Od1-N(^`a=Uo^ElX>xpq zKgW$Yl326^Xl2)k-vH=kTs*7&k((3#bqHl5tG$V&$gEW_|82nrXDuR6Q6s>A3;_gG zh6n_N_n&;H;%@0;Z1KR6a+aU9`e{6x%q5jkci>Z|N( zh!U&|6Fx7nYRTHAaXkR0LG6axPOJiwBD5sbCqdDsvo;TF#rQx6szX^pDAwyJ#^deX zC*P#wQyoV6z#p?-(QzgX{|KyH=kn~e^ zLF)ydxS5|!4-SDrPt4|KCsm2d>oG1RF&|5rRM`u-&mTZ9++P+@pj1iNiEAsYIPScl zwS0ID1r`LaZAhNFEe`3is1#)B885F2QWkJs6t{EEUQs2?Ehxa^)Ylg($XjG}ON^2w z9+8t|aS18pgN)yap=tP0LKV<&O#7@y(S8E^#^o#bC5|YyE$UBHRzEzO0g{UrU2I~4 z^Mrf0D2W!UQZqHm^kt@~7g1CZ7kFUXb&Q?sr$Eu(6!E|n5y9txLgqlkX0eB6p@-&D zB*Y0k=7Ms?Y>5YFqudMN#W^THW0E#`aIf{THmjL`S8}oUO#CUGRZCEj6*`3pt`R+@ zwve`l~GE83j@Fe7*Y3y=&EBpN{mM;t}Pp1 zNO-c6>X0l7|0rq2lF~_7OcP%fLUD@^&LrhMMM8LgNk*3gu(m3~D*aL8Ya(&+@5PJQ z$tb@P-nDCTk)R-cF=2xf-C%tcLh*|aCLr32lRjnUc-AQkV>2{SpK6 z{HFB>hBH8_G=O^GhofV{wPj3XEP}!i{%Ph$`CbanC=2m-O)s zs^L!W=^yu0E4q42bHtX{OmbwFJ$;Uji}=wQiK5akhfMUPk25T*a!9Qy#<-Ol>|8WK zv8veoCcIY3{wz_|2j*8owTI?gbM0{l)`aEBu#cGez0xWK!AXw#2S*pi!j~TkvBR2F z!g`{h!4{2glCjhHUdp&q7XgefE=Hlo!K4G3DY`lvHM#5=RF{;qpxEL7%jj18GS!5O zpXC|_g6C?KuZ>`g{(&HAf*W%IrA|mZT8|yCMwfe0br{BVdEO5GMEJreVN7@uZD}LF z<3{S?DC$s3>wwL*q;#rCJ+E%BNR@6*uJeqzKVGD-^UNDY$GyC7s=A4QapQ}HC-Xj)=~r;Z0x2bk$-Q-VmUx!s13@{XA3*O-$$_`3vC#fXVNq+(zGlz(r+p!U)apfAs&2_ z-nxf;cFg>444|)#*scwKTpQ!y?}FgZe<1S_G`>L7&D^5S+$Hjr@B5HNJ*3c12i(KY zXXBM6-a()VpHn}QcnO&peG_!?@J7>V|M=4v^n*DJTtNjPBW7P}zk z2(U)_jjo~{HtRYkd57G|zfSEJ$U*8s@~E0=l&}1UV~61CDoDpa!aQL*lR}ZdSr=g< zo#x77fx1F!0?*ELGGB_9_gsRdi*K3M}MUqi3 zm#^j^ zsTLuygiO#f_*ft>s}uBFU<~mRER!6HaIE{RMz`@__Sz7*8HFHr1iKQbzdPUxDbYR> z1#rRWRyTH3J0%5%F0aiQuS?M-&n5;H=(E_8LXxD`EA&;VhgFw;r{lAbkZs|}a9yj+ zZfjra;pWruFy@y!8%Az@NXP2z=}1SXMa}A<=w{5A1LuYKpi`A;n~}mhhk(3fs_JSm zTFFsoFf|vim6A1FdavX}o(+`rDajjrSrv&Z?_}bguPpF1e}U;?J9CRuH^mT>16*vw zl>>->UzIGs}Sm`pQ5kq5#MCw(w5i`7o;jR`Jr09Ix%{3LQ&7?_Z zHnPS`jNiRPf-NZPX3*A2k5vHhh!^F39C9(EFi zPgPR`a}E2_C7s4dYey$Bz&W}Sd1(A~v68x*&Gs%s0~4-IUVu(wX_z|c6Xs4*IQ|$e z2i}*29LYtEXQ8KYxKgI;4>x&TXyZTqCW>tdEMeBaU_uQ+aFL=c3Xd$_17c!>d*Fm*3Acu8h6>yRP=!K6cCwqtHYNj=p+&4PkDl_42CW78#+Bo zJj_EfGOYNO@OWdNX&SAO;%G>q(9o6f6=Z2@%AH_9M5*;dO+T{Ir9NA>+{|xEw$UWB zx?W1zOj$nkd5$yGw9McG2z@osd==x%8Mm_9@;g$Sy1eiC#lj~X+pw~@+Ms$llX?gp zDIZNPJq8P^5RV0q(AkMl-MSU1UfX*Wg%FZ#lnm!kW4))4=@s8Nw?A*?SB6MAwRnBQ zZhc|}bH)=KPr{Q4EwL_StAQQ<*$Z8~BvFKmB=J^VLjRF73vr8l1D(hZ39~x8KIw{@ zVHB%BMzAt1btZq!K;l)&)bd-@6gQqd$+T)JNhGa_+gEB)&eQt!_vXXW*KBQI{=|#K=UZQN0Nvlmm zxU)iamk-tR^RL_IA2)<0x4TVsc8&A1GfkJyyJDpJqWgbM&!D%s{T=}wr_(~j(j(Sa zS6`gPyFXCC#g1|RuR8=mv=zLF{wk8sm^KKJPrM2qkD^2lYR|uh+*4q!(-HD!)s4AP zU%1KBCQP#xz40U)gg)WL{<|^uhpt5E$kHJDau?@V4yRa);RyG>6P{yR>~GyLeV-4` zu~Beg_5 zk~OvNqm^>^AdWdxNYk|9%fw{8M5kSa{GB1Ya%%o(AHtrZuJ1sIn^Sb$$aEo%~Dz ziS5rXHCYFa`mU;9Ar%P)%bMHPzy6zw%Iq002aPPj(TN5G)Xw^U3hYjvB8GqWKH`>k zhBh|;>ep}9hV(!cL-lL)ZrjiWp-Phmkz&NB3MMTULJ>r%P(}qou5*y0AL|2nv{8n4 z8GxdRf_n=|u~G_wqp_)9{-Y~%K>urPBWt6BHrLN8mE-0rE5rBOd*Q_6@MYtMI0FV# zrA&sXR(J~ruY6VsrdrVgAS^-CBwb*P$}LmSh^AdS>j`74Xptn0LFG~}oJQ@EA*?~u zq*Y*z+OA$e2lGU^SUKwoqgSh#CoDkq7}Y;2?5<_eE9|awiVwSGUGPEc(i4JTH`}T{ zUb3dXo<`wD>X8E)K~dz9DB;}ZLYRiopo}ops7ya~QtQgA)teN;TYfUu$E!7%G{mdb zpCsbpM5%yqFt*35HU0xq0o!AKG^s?=XM0Rw#|DtF*nia`9)H6?o*4^Z&&5TSJ8?ME zJ&!JV(p{IFC_IyPl2}mx@&Z+`I~-%reS9$CQLx(|o8oN?q2TdoNTO)HKV;9{oKDi? zZ407szdz*R=F03ona8*LM08?FbapbYIQxo5adI-JbH+WRbm3XofjMEPb!PXf6kdAh z!q@PYNzpbZB2k%^oxbD>vc~qaahcw=hyU`Cb9ZiB2-=SjAHuj6>q$qZ0YM8I4wM!I z;u3kRVczEdS~%lV_&8IAsc>+-d)A4ap1^}{ccqA#NEXkJ7?iG_B2ElYhaI% zFds^yapg>i6fY-d`k9;(=XQSA=K40@s6t`%vBir!cHE`;;Ah7|(%Dm$XrH*aRt%nP zj@?P*n!LTWMAA;=HYzWa4uowkuC}CVob~0iNA}e=_n=G5#Fg7!Dww=XQsdg()$=~Q zAelLn0^!(gU=&UKTr_7BXIG;y9s~@=d0Qq+&NY3fn4nX^C{l_!`v;wP#SK3N+Uw?M zL7~X&P&}vR9rZamq`q*Z7-Uc8-Fa*Na3N;spM8@Y-J&FG(4i5CMPrJKL+qR?8vViw zF~w@(+^S#Yb3KdqP|Yjl25S6k42u>Z3`Q)Ne3*y%_` zd46UOlgIh?V95auBEIK>ZRrL>t3sKHLYebInaop3{^I$VRe07_^i1k$*p(B}OX+ni z!izyCL6eMR()}2~6^6FIn2w5@|19YmbByL}#O5B|Pm7+sxOg_-UVUhQn{$b_MfXsi z;0Q((iZafUium4bGY?E)Ad>1cyJ1biKkF#6rss&AswHf0d^1tai8eXDZVm&;NPRmPbwC z!A>pM-NyJ5?6YGq3zFYiys*&KKXGK`t{*PP=Ezgw>$Y6LN@v%?Aa}D#%c`wb)M;zWyiVP3VD{1X&R9A;)!lV%t6#fsxmVM?b9+731L{*2*Gdkn z=KanRkH!bE7mw^+sX9RO(%4g^_**^Tlj5A{Pe zC`ne&iU)}@6&e%nWdJ!e5~Lq0Fi(bITsL2bM7pm8S(e)6W!OTj{0ZJ1LM(D8x?f+(OAj`~ zX+a~T)~gcp32m_zVX-8goE@CHi3pq--76>bO6}q?51zXMmaB%HyJ)~`rELjDE)M?V zRFfrti@*h_cT)Jv#yBv`U!Xl9*XFSWyc&D)7)Z`(we6M8$FYA_{v0i0Ay+6#VZcucz9!x<`=9 zX_U6qY4D*hyRO6Hm@yKY{fG_#G|7H=TyIw0CT z%cn^ovx#aJ-NOpkC(b+up;w?@zpK!}}IAP84U1qQ;_iGA6n=#?znl&=g9EARDrl4)fsajd&1S7?9?(KmrL5L=xx? z(-%|$F5r>; z>+8C}@y}DIU^!GrG`oN%dIs`Szp;MzeNz4jkqiAET zcyN!>!hG7Z64-hzN*taK6P;N0%B&l&+pYO2*)|H?AN8h}tJAsP)#5s7NhxZC?!09v zw)*gy{_J_888!kg?loL(U_X>?1w+U= zY<2=w37l2o_0jV)7&peJI%zG7q;8OJtec(& zbpyN^lvQT-XgYI}K8XWgIO~xvFN&NR1aFobCheYv!jT*~3X~v3V+%Y|Xk)sJn!w`O z55EX9>qM?Hif&r7TYXzcDrngNc3YTe7#8v6r;TsIvpfS*5?xsvgb1 zGtr1>V|5Pd4>epH3G%bCCF?7u8%T_)UVDKmaY+&e*d-+Esv7XBCALi#j82fiUF~ib z>+8qsuC-lpxt+l#EJw+m910IOeHDb^02Ka^d>D>-Z_JXzf$VQbbbz3|vGwfVjv0z- zaR%-%>As0I?#GfOS9&$*v~G0zYT!7anFZay6qK)WcA2_mSN_Iv!kw z+f85oS$(K=sCBSK3?;Zj6E|o;0HTCGdk1bnk75|D0^!GaT(p|SsP30R`&NrkaHm*FJyl@sNN?iAjbM?*1#>G_5|?;+ho|bblXzqTNpPM^=)e=;LX4# zcSxw*Ivq>y!?sJeOvG-WH~33=D+qhj_doSAV0W-{ogK}D(@@+QL*OHdOQw)UOmvEr zNOk#hBNFLeMNBBX7?6R9yLylv7~MOFUO-J*sJEogNbsNvVf<-)FkaCxy_Ks!SfPEG zADb_+UcKU`OR@S(8N@~yt@)eJpFfxJ8=ht@c3K3~ZgTC3;%-(pX_wouT+}7!JECw^ zdZx|4-OxMZ$2~qk*KqfoK>mfq4fLks~3({Yp65SyrJBHnBpzi_7 zy$h>x7K3?=E1%Kj4;+(hKQHL3$5|cDUiXh&BE3HD!~H#5S_p6;(~tZ!Fkn<{BVD$- zsn>dHVF=;Z8IBXsh_NMwTa$??)f@aBM!>skO#mRb!j@2Kl8N-e2cl5F00{6KAXnWC z%)dA?9$J@9>{X&N?_LKI2S0L5K*@Ryh%*4B4U*;DFC@MM>Hz!KYVzEjGCh`hSW}O3 z(BA@cJ~EEbF;a~-C7VrAKHhOeRx0oZM$y#6WjuMBJM$~!i8Uqlw?KU$lReb3*9BS&g_juIk~8&MRg@>3Gjs7oo!1C5FuO_GLT z7yiFS&N?c}t!?8B9fHIl-61K`-6bGHH_|5 z4@C*{twT7kLLM#*qUmi7s=&;OirKg;hse?|QNFrKxB-?WB2sXIw!L4l4Hobefh5r9 zuV>tGGl96t0g<`TqVmPR*uQXp5C$J)1XZImrUc+fT8jcRzCHB%60nIK)^k%3noY+m z&FpW?YmUeAmS+`tGnQxbBZZ@h3}1&8YcI;v6q=O}rqkF>4qLH%&aJ@-c_4}~VBj*z zf<4Xm2fC;|23v}XZje$E%BbX)z7;N&n%-Y$^G1+X}x}?k$ z@}ApX9ax#xvcB5j8P{t{J~w0H#{~$(b|bcJ?m`bU0FSK^$MxE(QD06Wj?W4`7DOC( zLmXENZ2Hoc6x}y%0tMk8Nw4`_VN`$@biq^GsQ?59eA5B zZw^`;Q<5(Nml;O}+gu13M=4%lW->0wk&N+m_-vzv?y<1r#Ls&kSk9~BC^iyML8+*q z(x=&v4zu~Mdm;t4XPSIG;^*B3Z-wpf7V$c2U2>qTrxT{=+jJl5pnRSQp(dA-sP+0&l zFo7e&Wd6;Q9j%?akV_U0R_rgq1wm*OI37AaEma(de|>i^G*VN{qQf^1f=batWu*P1 z!!A*S*9>Hqh21CinV)==PVHq)@Xu2}aNQ;mn3vSJ9D6NyH>u|=xEXryDJBvsrqJ0^ZAGjxv7m6I95%fsH(!bk z!J1qDC~A^YYx~@E&dPL-q_1`|m+%O!9-khN5PE~kv_T`hKV60WB4ELiwvWs6nJX7l zDDAptl@ulI4*z4$S9&B5A8e3)di^%`>s5yy%Or@SspE-X{T-Y}{aMUX`=r+0kholq z8O_pNfl_uV)nJ4 z0w6YFZ%ZO~B(Q2U&~+rxl^MmgEL{a%6WhkXV z%@Oy(2JZ~NAqXeFC$M{5{XniE;nf<8U1+mm8DpJDpb$+KlS+=pdljTiY**~UWWFF{ zHkE9pwIX+vwYTfG)q0sA(Kx3>>#>X_B&NS&MbaqaxIHqw>xk2dE;wptpGBzpj6Cy4 zjjQfREXl;}9$v0eNWx-Kz7+B&iq;2G)g(q>I)9#%G+!-!q^=B2p{TwAk>*k&(@iLj zes<|7@teqTksW+D@x7`2;R1kNeUN*YnRtnx$?7;zw}yz`M0N-vE8MtuXXF`ZX}?oA zJ|#x(8SOP%2Px-b%!a(sIrWH0wGo94K)(!!y$+XM=dRGpvG?3-vM(4o@>7pYUw3R% z9|(Cf>-R}Q`jyvSq)D<*pe{1kjo~dB`JT#n3-&5o2b9Op*_6(MHYHj?Vp4UuB}6wg zd5(k&EnL_OV=Nb&h#8|mPZ8f2_J8QAYvAMA0eJ=B)p!nfg(vtO&joXck zLs|94ez!YBiA^J`0=)5UeX`MZ`1AK&9&<^ z4^*rOF0&fp>8q{xL_~ysJP*%ekb`J4MwYpT6gJDT*PN*Q{l{K7tczA2nRqA-=EPUH z_ivo|a6PmcFQ2NKYXQ4kmGF-W!zZvY8WHVGOlL!D*mw1Hbw-msBHzwPqsQ^m69+wS zDQSsmi3-XwbINT>u8j3_w_lA~5Vy~biE-%WB5nQNKS&qgzHPfS=^awgtdF;?4Btx&?+BxG znkC=6x3XRY~j1EzjBK*vm1*qbH-X%9P^l7Kw*@B7iO)`PN>^m0HSoi2V zCo%~;(xRL=%>2!=1cPWJS`j#O*^*{21_JWAOfbt45z|0?9>HswmfhwrvIK%6v(8bs>E;y-|Bu6`A+ryN0vPuludFVGG%h$m|m+SAEY*YxojK6}n5O8b@tdM5xcXN(ra(k3RQ*8>pz-Qe*jG2hApV z1iNW<6eXwLPNd6)WU@Fg^|Cs?1tXFz+OfOBwv4PcH0w0)k|;ppPHD;9tPrW-C7|Z6 z$y`F!U}2h6AW(_f3ybicR00@~%F5sCI%mklimKI(tCK@x zqa4zap3c~S$jO=RLXf0a_>?)}<2cy;FSvb*skdhmFd?GtT%Kq4d)q3~Q-jMG5>lTvl z*EZw1b`P1N3*EPIMT^OybNAHyP4{w3apYRluRteS702e44M0em&+GY7u~1snC2Pa9 zkOMG({$Kt29t%s9&ZFsu;JfQwuLet=H2|a+tR0XSL;f9-&H`Nism685B+;713$KXl|4=iWu#M;7(_c);)Dxxp$>Y^R z-7~`{xU8$H6;`Vo*KJ$GuDT2j)m$C&fOItpatNOzdrVq0w@>RUf6SGO2=--A0l!YJ?f5p*{oD=lajFNdLbSQ z`Krj)p~pA19^nygCi$N+Z0eclu;(YeS3Yt8ZZ zJrhzE*$38vJ%%cuo|@gMeuC{ZZABVXgh zXig=X)Xp!q(3iVdGWWY{aLQSWmKqQ7N_EVxf!I1=-Cd-MI^!(+xN2B)Utp7YW0_=; zZukhtJEp-a6YT^*xs>9i25mo`0vmpxZkTdfVrlLoZ|z85bnq#i&;Qb5F!=al>(E)z zHDg$NN364e+<4jUDW{*TZ;xZY0$Q2MO~2@w4`UFiP01(o9Y3R4s-wvRPP+3Dp94B5 zrP$g96#UgFyE(;Fe4#0k^Qppqx<~O5G|VA&R#84JRh&i#kfUfUG~VJk(skih3(Y$w zT<}*|ux|Vyb+xBn2Ep+5N;*g4-Wbe?=N|XncydHx@M-)qmgk0`l@3}E>16HU(l0Kf zDogcF?ts;xRpTP~fq%i56um*J8*w^ZLxbfIrL~+#^~-MzX*wShy?{*K*Xb8IkJigF zeDGD5@WXgw4;^>r^|Kf!4mEUTV6KFhYQJ?U(|bfU6XEIT&u*{PGIls+oeLCjGo#xC zW8@T;Xaa|pDIr-pqxH?)Um0=NLU{s7Tk8V&1F|w?uS*YB;_B9|6dMw^friPzV~BV|B8zz5zAB;2qE;+4J^23I153hnttEoaezVLD}_d-(yDZDcx-@7wHe(B z!t&+13K2hr^(tdQ+24aPjN}jWgZ3p39Io$)+@+hDMQ%+oU-Ptgt>zc09H>m+|A2ba zo{_!|n#OJT$|u+f1TThlq95c!%)ULrG`$bRGX?M)(D54(%;%7to8gJ%pd{rGYMEga zcMZMd@RVf#9+VSJW|kUL*Xca4-{t4wgY{U1=+hqFRgm*nl*+IKBuXPHh?* zu%sty2{@%KckV5hT&XNiShgSPEx&xKDdsRk+vH|t;nS|PdKJai-y36P!6|po+Cn;N zmspN(pjSO=S67a&zqfmYJ*LN$oDA>2x$5yO?XDJHX3@|_!$yx3c*9=X;BX;K>RP$( zGhh8Zkp^)Zr{Q>mEe)*ki}4};s~y#J(7dvUn{`!ssJhr@q?_u8P0tDb=U5}Opm!B{ z;82gK_Qv*3yALLW2D%&C*J?ei+=nF`>2q$oUZninwd3OToeZ5#FV?wMo`9NJRV8Ot zo~RlQ4j3sm?^I|S+DqGOJcqD!0thO*rK$_quil9|2!#_7>ZObeFgu#1hNKMJxnL1^ zBo2b3kA(7?yOqm5W{nEQS}oqR9~<;%tv?0VZ=ZrLn$y;eE?OWY^=bU0NQKMXt4*L5 z#JLGun+=VV2GTQy1laFb*yDDf=no_Qj|VRG z&*5jhDCW;5c?1Li0x^OM9a5<6(HMY1&AXZua~$w%4qx?l2q}D3T3F#9p{1}$QuxA3 zK$jdKtl+Qle<^(DXKug`p+Drx|6TZJjOl->{)+-H`*zqVylj_$RR0-$3Xcf>G)hbi zTfnao9wCnK?*dYPAz=CuUjGU4KgFfO>oCqI@Z@+i0nnn2eGRUk0N7FD9#uGu!@Sb~ z#9umY$A!Y{Acc8w|Njd8+{m9xm2~`X;i2#%%;IwN%3+()-109G9&*@!6!ClVCA^3U znD^$kh`)0%;b}QzmA}!vig9kyZfB{%(+*(H$XhhHWHopiiQ%|!+u;P@pW{C_`1gDZ zcv?T~G~A}$PP>4o28|5;wnmFFtXpgRaan&i#lusvNd7?mPZoK2JZ;qcZ+MRkj6dRk z_i@AHr%C@C{%=<|Jh@%|^G`C4e%#OV%ou?8NAmAZVtDc}EK~K?cEd0HUoE)sP{fGy z-=OQmx4%TUowe{#9+=Vg7W6ltEj&+6R`(Mz`Xu0=Bm9}V?M#E`S-{-Ww|Ia1(*EpI zgO||kjlYJPKLPl)&u@e8+}h{c<|%jyG7Nu|@SBwip7`E3@{}^-Z(>B%J248_9DdQa zEl2Rg09b?dtwqBdkl=AWn3_oMnkE3xYbWe~jFYPxKj-kc+YQ|CxNKO;#4X$(+qvPn zz)Br(ciRLYXSEReWBfIT=icrwgy%kk#W~;R{;As#p6jh=k|L2b0T4a;*B9s49G-jo szSeJCg+FlN?sCD?R_hA7ew^Tcj;cy1Ft->20s-vlgpPoqqWNR?e@q(Jxc~qF literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jdk-1.3.1.zip b/src/test/resources/zip/data-java-jdk-1.3.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..a24e9b775b74d2315e0f953873d37751dfe96077 GIT binary patch literal 21620 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 IqQ8^<6Zi53od5s; literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jdk-1.4.2.zip b/src/test/resources/zip/data-java-jdk-1.4.2.zip new file mode 100644 index 0000000000000000000000000000000000000000..fb1dbc40d5e6ee9b83a71d1801ebbe8238a02722 GIT binary patch literal 22059 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jdk-1.6.0.zip b/src/test/resources/zip/data-java-jdk-1.6.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..4a9858a2a203bf83e90c4c142c3ea344d9944ceb GIT binary patch literal 55625 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

0IBU@LSizO78C|KaZMRZ3J9Y8Wfh&2XG8>( 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∨fWY8FF+0(<4xk%w>cL%+Dl`Dircy*k;Ky@R)U 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 Q4VcOdXZRTy3|l}v0NHH#0RR91 literal 0 HcmV?d00001 From d3bb0319301e81c28c098a3fb70e979dcecca86d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 15 May 2019 08:25:31 +0200 Subject: [PATCH 003/211] Initial commit --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0db611d7..2ead373a 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,10 @@ generate _"build/libs/jd-core-x.y.z.jar"_ ## How to use JD-Core ? 1. Implement the -_[jd.core.loader.Loader](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/loader/Loader.java)_ +_[jd.core.loader.Loader](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/v1/api/loader/Loader.java)_ interface, 2. Implement the -_[jd.core.printer.Printer](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/printer/Printer.java)_ +_[jd.core.printer.Printer](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/v1/api/printer/Printer.java)_ interface, 3. And call the method _"decompile(loader, printer, internalTypeName);"_ @@ -103,8 +103,7 @@ Printer printer = new Printer() { 3. And call the method _"decompile(loader, printer, internalTypeName);"_ ```java -ClassFileToJavaSourceDecompiler decompiler = new -ClassFileToJavaSourceDecompiler(); +ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler(); decompiler.decompile(loader, printer, "path/to/YourClass"); From d850ec4c3fd00a39b3f04f3aacbc1995ea968457 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 15 May 2019 08:46:02 +0200 Subject: [PATCH 004/211] Update test resources --- src/test/resources/apk/ContactManager.apk | Bin 25931 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/test/resources/apk/ContactManager.apk diff --git a/src/test/resources/apk/ContactManager.apk b/src/test/resources/apk/ContactManager.apk deleted file mode 100644 index 418f504bde28ee5fae806e2e060f488e7abe791f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 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 Q@CA_y;SJ_Rp)sWX1&8eh#{d8T From e986b2995b29fcac9ac9d30b0b8b2fc8c893763b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 18 May 2019 09:56:22 +0200 Subject: [PATCH 005/211] Fixed #240 : Double Quotes aren't escaped. --- .../classfiletojavasyntax/util/ByteCodeParser.java | 2 +- .../javasyntaxtojavafragment}/util/StringUtil.java | 9 ++++----- .../visitor/ExpressionVisitor.java | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/org/jd/core/v1/service/{converter/classfiletojavasyntax => fragmenter/javasyntaxtojavafragment}/util/StringUtil.java (88%) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 0809e83b..541164e2 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1043,7 +1043,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in break; case Constant.CONSTANT_String: int stringIndex = ((ConstantString)constant).getStringIndex(); - stack.push(new StringConstantExpression(lineNumber, StringUtil.escapeString(constants.getConstantString(stringIndex)))); + stack.push(new StringConstantExpression(lineNumber, constants.getConstantString(stringIndex))); break; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringUtil.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/StringUtil.java similarity index 88% rename from src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringUtil.java rename to src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/StringUtil.java index c2191f3d..4d7fbda0 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringUtil.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/StringUtil.java @@ -5,20 +5,19 @@ * copy and modify the code freely for non-commercial purposes. */ -package org.jd.core.v1.service.converter.classfiletojavasyntax.util; +package org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util; public class StringUtil { public static String escapeString(String s) { int length = s.length(); - int i = 0; - for (; i < length; i++) { + for (int i = 0; i < length; i++) { char c = s.charAt(i); - if ((c == '\\') || (c < ' ')) { - StringBuilder sb = new StringBuilder(length * 2 + 2); + if ((c == '\\') || (c == '"') || (c < ' ')) { + StringBuilder sb = new StringBuilder(length * 2); sb.append(s.substring(0, i)); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index de3ccba4..a935ff6a 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -24,6 +24,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util.CharacterUtil; import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util.JavaFragmentFactory; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util.StringUtil; import org.jd.core.v1.util.DefaultList; import java.util.HashSet; @@ -529,7 +530,7 @@ public void visit(PreOperatorExpression expression) { @Override public void visit(StringConstantExpression expression) { tokens.addLineNumberToken(expression); - tokens.add(new StringConstantToken(expression.getString(), currentInternalTypeName)); + tokens.add(new StringConstantToken(StringUtil.escapeString(expression.getString()), currentInternalTypeName)); } @Override From 9cfcf7d820ad5f578b3a9f6e84d871b8eeafe6c8 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 18 May 2019 11:49:20 +0200 Subject: [PATCH 006/211] Update version to 1.0.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3038fffc..9607ea65 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.0.0' +version='1.0.1' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From 4ae2ddc4fd6a81a4673d85df04f873b5da3a735b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 18 May 2019 22:23:38 +0200 Subject: [PATCH 007/211] Optimize ternary operator --- .../org/jd/core/v1/model/token/TextToken.java | 1 + .../visitor/ExpressionVisitor.java | 40 +++++++++---------- .../jd/core/v1/ClassFileToJavaSourceTest.java | 2 +- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/token/TextToken.java b/src/main/java/org/jd/core/v1/model/token/TextToken.java index d8fa983e..c8648797 100644 --- a/src/main/java/org/jd/core/v1/model/token/TextToken.java +++ b/src/main/java/org/jd/core/v1/model/token/TextToken.java @@ -38,6 +38,7 @@ public class TextToken implements Token { public static final TextToken SEMICOLON_SPACE = new TextToken("; "); public static final TextToken VARARGS = new TextToken("... "); public static final TextToken VERTICALLINE = new TextToken("|"); + public static final TextToken EXCLAMATION = new TextToken("!"); protected final String text; diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index a935ff6a..5853d2f5 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -558,44 +558,40 @@ public void visit(SuperExpression expression) { public void visit(TernaryOperatorExpression expression) { tokens.addLineNumberToken(expression.getCondition()); - if (expression.getCondition().getPriority() > 3) { - tokens.add(TextToken.LEFTROUNDBRACKET); - expression.getCondition().accept(this); - tokens.add(TextToken.RIGHTROUNDBRACKET); - } else { - expression.getCondition().accept(this); - } - - if ((expression.getType() == PrimitiveType.TYPE_BOOLEAN) && - (expression.getExpressionTrue().getClass() == BooleanExpression.class) && + if ((expression.getExpressionTrue().getClass() == BooleanExpression.class) && (expression.getExpressionFalse().getClass() == BooleanExpression.class)) { BooleanExpression be1 = (BooleanExpression)expression.getExpressionTrue(); BooleanExpression be2 = (BooleanExpression)expression.getExpressionFalse(); if (be1.isTrue() && be2.isFalse()) { + printTernaryOperatorExpression(expression.getCondition()); return; } - } - - tokens.add(TextToken.SPACE_QUESTION_SPACE); - if (expression.getExpressionTrue().getPriority() > 3) { - tokens.add(TextToken.LEFTROUNDBRACKET); - expression.getExpressionTrue().accept(this); - tokens.add(TextToken.RIGHTROUNDBRACKET); - } else { - expression.getExpressionTrue().accept(this); + if (be1.isFalse() && be2.isTrue()) { + tokens.add(TextToken.EXCLAMATION); + tokens.add(TextToken.LEFTROUNDBRACKET); + expression.getCondition().accept(this); + tokens.add(TextToken.RIGHTROUNDBRACKET); + return; + } } + printTernaryOperatorExpression(expression.getCondition()); + tokens.add(TextToken.SPACE_QUESTION_SPACE); + printTernaryOperatorExpression(expression.getExpressionTrue()); tokens.add(TextToken.SPACE_COLON_SPACE); + printTernaryOperatorExpression(expression.getExpressionFalse()); + } - if (expression.getExpressionFalse().getPriority() > 3) { + protected void printTernaryOperatorExpression(Expression expression) { + if (expression.getPriority() > 3) { tokens.add(TextToken.LEFTROUNDBRACKET); - expression.getExpressionFalse().accept(this); + expression.accept(this); tokens.add(TextToken.RIGHTROUNDBRACKET); } else { - expression.getExpressionFalse().accept(this); + expression.accept(this); } } diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 5ce78199..bdc70e7e 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -1051,7 +1051,7 @@ public void testJdk118TernaryOperator() throws Exception { assertTrue(source.matches(PatternMaker.make(": 15]", "\"1\""))); assertTrue(source.matches(PatternMaker.make(": 16]", "\"2\";"))); assertTrue(source.matches(PatternMaker.make(": 24]", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); - assertTrue(source.matches(PatternMaker.make(": 34]", "return (s != s || time < time) ? false : true;"))); + assertTrue(source.matches(PatternMaker.make(": 34]", "return !(s != s || time < time);"))); assertTrue(source.matches(PatternMaker.make(": 40]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); assertTrue(source.matches(PatternMaker.make(": 60]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); assertTrue(source.matches(PatternMaker.make(": 71]", "if ((s1 == null) ? false : (s1.length() > 0))"))); From 6ecf55143c381b167ca68786a0a726e5ea27e069 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 19 May 2019 09:46:26 +0200 Subject: [PATCH 008/211] Optimize ternary operator --- .../javasyntaxtojavafragment/visitor/ExpressionVisitor.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index 5853d2f5..07ee7a9c 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -571,9 +571,7 @@ public void visit(TernaryOperatorExpression expression) { if (be1.isFalse() && be2.isTrue()) { tokens.add(TextToken.EXCLAMATION); - tokens.add(TextToken.LEFTROUNDBRACKET); - expression.getCondition().accept(this); - tokens.add(TextToken.RIGHTROUNDBRACKET); + printTernaryOperatorExpression(expression.getCondition()); return; } } From 3758e39dbb522a04cdf6c929506867a8d01a1152 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 19 May 2019 10:28:37 +0200 Subject: [PATCH 009/211] Limit the excessive time taken by layout --- .../service/layouter/LayoutFragmentProcessor.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java b/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java index 8ba39926..89f80ce4 100644 --- a/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java +++ b/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java @@ -55,8 +55,13 @@ public void process(Message message) throws Exception { UpdateSpacerBetweenMovableBlocksVisitor visitor = new UpdateSpacerBetweenMovableBlocksVisitor(); // Try to release constraints twice for each section + int sumOfRates = Integer.MAX_VALUE; int max = sections.size() * 2; + if (max > 20) { + max = 20; + } + for (int loop=0; loop newSumOfRates) { + sumOfRates = newSumOfRates; + } else { + // The sum of the constraints does not decrease -> Quit loop + break; + } + if (! mostConstrainedSection.releaseConstraints(holder)) { break; } From ca0e165a9ae29ee3b8f8d66155aaab4a4900adba Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 20 May 2019 22:51:09 +0200 Subject: [PATCH 010/211] Fixed #197 : INTERNAL ERROR --- .../classfiletojavasyntax/util/ByteCodeParser.java | 2 +- .../visitor/CreateInstructionsVisitor.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 541164e2..321f9b5a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1295,7 +1295,7 @@ private void parseInvokeDynamic(Statements statements, DefaultStack synthetic method + method.setFlags(method.getFlags() | FLAG_SYNTHETIC); + method.accept(this); + break; + } + } } } for (ClassFileConstructorOrMethodDeclaration method : methods) { From c010755cae2f5a18b877eded30502adf2a33f2db Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 22 May 2019 07:27:08 +0200 Subject: [PATCH 011/211] Update tests --- .../jd/core/v1/ClassFileToJavaSourceTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index bdc70e7e..e0699538 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -114,6 +114,7 @@ public void testJdk170Basic() throws Exception { assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -159,6 +160,7 @@ public void testJdk170NoDebugBasic() throws Exception { assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -195,6 +197,7 @@ public void testJdk170Constructors() throws Exception { assertTrue(source.matches(PatternMaker.make(": 39]", "this.short123 = 3;"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -253,6 +256,7 @@ public void testJdk170IfElse() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 184: 184]", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -281,6 +285,7 @@ public void testJdk170Interface() throws Exception { assertTrue(source.matches(PatternMaker.make("public interface Interface", "extends Serializable"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -325,6 +330,7 @@ public void testJdk170While() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -364,6 +370,7 @@ public void testJdk170DoWhile() throws Exception { assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -422,6 +429,7 @@ public void testJdk170BreakContinue() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 162: 0]", "break label16;"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -499,6 +507,7 @@ public void testJdk170For() throws Exception { assertTrue(source.indexOf("[ 448: 448]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -535,6 +544,7 @@ public void testJdk170NoDebugFor() throws Exception { assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -575,6 +585,7 @@ public void testJdk150For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 423]", "for (byte b = 0; b < 3; b++)"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -615,6 +626,7 @@ public void testJdk160For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -654,6 +666,7 @@ public void testIbmJ9For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -699,6 +712,7 @@ public void testJdk170Array() throws Exception { assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][]", "{ { 1 } ,"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -740,6 +754,7 @@ public void testJdk150Array() throws Exception { assertTrue(source.matches(PatternMaker.make(": 75]", "testInt3(new int[][][] { { { 0, 1"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -777,6 +792,7 @@ public void testJdk170Assert() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -814,6 +830,7 @@ public void testJdk150Assert() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -858,6 +875,7 @@ public void testJdk150AnonymousClass() throws Exception { assertTrue(source.matches(PatternMaker.make(": 104]", "System.out.println(\"end\");"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -920,6 +938,7 @@ public void testJdk170Switch() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 288: 0]", "default:"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -960,6 +979,7 @@ public void testJdk170AdvancedSwitch() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 40: 40]", "System.out.println(1);"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -990,6 +1010,7 @@ public void testEclipseJavaCompiler321Switch() throws Exception { assertTrue(source.indexOf("[ 239: 239]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1020,6 +1041,7 @@ public void testEclipseJavaCompiler3130Switch() throws Exception { assertTrue(source.indexOf("[ 239: 239]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1062,6 +1084,7 @@ public void testJdk118TernaryOperator() throws Exception { assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1101,6 +1124,7 @@ public void testJdk170TernaryOperator() throws Exception { assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1151,6 +1175,7 @@ public void testJdk170TryWithResources() throws Exception { assertTrue(source.indexOf("[ 162: 162]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1201,6 +1226,7 @@ public void testJdk180TryWithResources() throws Exception { assertTrue(source.indexOf("[ 162: 162]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1247,6 +1273,7 @@ public void testJdk170Synchronised() throws Exception { assertTrue(source.matches(PatternMaker.make(": 97]", "return subContentEquals(s);"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1290,6 +1317,7 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1347,6 +1375,7 @@ public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1403,6 +1432,7 @@ public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1459,6 +1489,7 @@ public void testJdk118TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1511,6 +1542,7 @@ public void testJdk131TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1568,7 +1600,9 @@ public void testJdk170TryCatchFinally() throws Exception { assertTrue(source.indexOf("Object object;") == -1); assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); assertTrue(source.indexOf("Exception exception8;") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1610,6 +1644,7 @@ public void testJdk170AnnotatedClass() throws Exception { assertTrue(source.indexOf("public void ping(@Deprecated Writer writer, @Deprecated @Value(str = \"localhost\") String host, long timeout)") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1662,6 +1697,7 @@ public void testJdk170AnonymousClass() throws Exception { assertTrue(source.indexOf("} ;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1708,6 +1744,7 @@ public void testJdk170GenericClass() throws Exception { assertTrue(source.indexOf("[ 104: 104]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1739,6 +1776,7 @@ public void testJdk170AnnotationAuthor() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "Name[] contributors() default {};"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1774,6 +1812,7 @@ public void testJdk170AnnotationValue() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 27: 0]", "Class clazz() default Object.class;"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1856,6 +1895,7 @@ public void testJdk170OuterClass() throws Exception { assertTrue(source.matches(PatternMaker.make("public class InnerInnerClass", "{", "}"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1901,6 +1941,7 @@ public void testJdk170Enum() throws Exception { assertTrue(source.indexOf("public static final enum") == -1); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1937,6 +1978,7 @@ public void testJdk118Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1975,6 +2017,7 @@ public void testJdk142Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2019,6 +2062,7 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 67]", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); assertTrue(source.indexOf("/* ") == -1); } From d5a198dce6ae956c241cfb4d5cb942f295c35c3c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 23 May 2019 19:38:16 +0200 Subject: [PATCH 012/211] Fixed NPE when decompiling java.lang.Object --- .../classfiletojavasyntax/util/LocalVariableMaker.java | 5 ++++- .../deserializer/classfile/ClassFileDeserializer.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 0f1cf59d..a3cd0ac4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -74,7 +74,10 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa } objectTypeMaker.make(classFile.getInternalTypeName()).accept(populateBlackListNamesVisitor); - objectTypeMaker.make(classFile.getSuperTypeName()).accept(populateBlackListNamesVisitor); + + if (classFile.getSuperTypeName() != null) { + objectTypeMaker.make(classFile.getSuperTypeName()).accept(populateBlackListNamesVisitor); + } if (classFile.getInterfaceTypeNames() != null) { for (String interfaceTypeName : classFile.getInterfaceTypeNames()) { diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 5869cf47..97261970 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -101,7 +101,7 @@ protected ClassFile loadClassFile(ClassFileReader reader) throws UTFDataFormatEx int superClassIndex = reader.readUnsignedShort(); String internalTypeName = constants.getConstantTypeName(thisClassIndex); - String superTypeName = constants.getConstantTypeName(superClassIndex); + String superTypeName = "java/lang/Object".equals(internalTypeName) ? null : constants.getConstantTypeName(superClassIndex); String[] interfaceTypeNames = loadInterfaces(reader, constants); Field[] fields = loadFields(reader, constants); Method[] methods = loadMethods(reader, constants); From de7f67f97d7c03b093425ea47f0769d825247d80 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 25 May 2019 14:49:27 +0200 Subject: [PATCH 013/211] Improves the layout --- .../visitor/SingleLineStatementVisitor.java | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java index 50571f63..d1919b35 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java @@ -16,23 +16,35 @@ import java.util.List; public class SingleLineStatementVisitor extends AbstractJavaSyntaxVisitor { + // Minimal line number of visited statements protected int minLineNumber; + // Maximal line number of visited statements protected int maxLineNumber; + // Estimated number of statements if line numbers are unknown + protected int statementCount; public void init() { minLineNumber = -2; maxLineNumber = -1; + statementCount = 0; } public boolean isSingleLineStatement() { - return minLineNumber == maxLineNumber; + if (minLineNumber <= 0) { + // Line numbers are unknown + return statementCount <= 1; + } else { + return minLineNumber == maxLineNumber; + } } + // -- Statement -- // @Override public void visit(AssertStatement statement) { statement.getCondition().accept(this); safeAccept(statement.getMessage()); minLineNumber = statement.getCondition().getLineNumber(); + statementCount = 1; } @Override @@ -40,12 +52,14 @@ public void visit(DoWhileStatement statement) { minLineNumber = statement.getCondition().getLineNumber(); safeAccept(statement.getStatements()); statement.getCondition().accept(this); + statementCount = 2; } @Override public void visit(ExpressionStatement statement) { statement.getExpression().accept(this); minLineNumber = statement.getExpression().getLineNumber(); + statementCount = 1; } @Override @@ -53,6 +67,7 @@ public void visit(ForEachStatement statement) { statement.getExpression().accept(this); safeAccept(statement.getStatements()); minLineNumber = statement.getExpression().getLineNumber(); + statementCount = 2; } @Override @@ -66,7 +81,7 @@ public void visit(ForStatement statement) { } else if (statement.getInit() != null) { statement.getInit().accept(this); } else { - maxLineNumber = Integer.MAX_VALUE; + maxLineNumber = 0; } if (statement.getCondition() != null) { @@ -76,6 +91,8 @@ public void visit(ForStatement statement) { } else { minLineNumber = maxLineNumber; } + + statementCount = 2; } @Override @@ -83,6 +100,7 @@ public void visit(IfStatement statement) { statement.getCondition().accept(this); safeAccept(statement.getStatements()); minLineNumber = statement.getCondition().getLineNumber(); + statementCount = 2; } @Override @@ -90,28 +108,33 @@ public void visit(IfElseStatement statement) { statement.getCondition().accept(this); statement.getElseStatements().accept(this); minLineNumber = statement.getCondition().getLineNumber(); + statementCount = 2; } @Override public void visit(LabelStatement statement) { - minLineNumber = maxLineNumber = Integer.MAX_VALUE; + minLineNumber = maxLineNumber = 0; safeAccept(statement.getStatement()); + statementCount = 1; } @Override public void visit(LambdaExpressionStatement statement) { statement.getExpression().accept(this); minLineNumber = statement.getExpression().getLineNumber(); + statementCount = 1; } @Override public void visit(LocalVariableDeclarationStatement statement) { visit((LocalVariableDeclaration) statement); + statementCount = 1; } @Override public void visit(ReturnExpressionStatement statement) { statement.getExpression().accept(this); minLineNumber = statement.getExpression().getLineNumber(); + statementCount = 1; } @Override @@ -119,6 +142,7 @@ public void visit(SwitchStatement statement) { statement.getCondition().accept(this); acceptListStatement(statement.getBlocks()); minLineNumber = statement.getCondition().getLineNumber(); + statementCount = 2; } @Override @@ -126,12 +150,14 @@ public void visit(SynchronizedStatement statement) { statement.getMonitor().accept(this); safeAccept(statement.getStatements()); minLineNumber = statement.getMonitor().getLineNumber(); + statementCount = 2; } @Override public void visit(ThrowStatement statement) { statement.getExpression().accept(this); minLineNumber = statement.getExpression().getLineNumber(); + statementCount = 1; } @Override @@ -143,6 +169,7 @@ public void visit(TryStatement statement) { safeAcceptListStatement(statement.getCatchClauses()); safeAccept(statement.getFinallyStatements()); minLineNumber = min; + statementCount = 2; } @Override @@ -152,7 +179,8 @@ public void visit(TryStatement.CatchClause statement) { @Override public void visit(TypeDeclarationStatement statement) { - minLineNumber = maxLineNumber = Integer.MAX_VALUE; + minLineNumber = maxLineNumber = 0; + statementCount = 1; } @Override @@ -160,6 +188,7 @@ public void visit(WhileStatement statement) { statement.getCondition().accept(this); safeAccept(statement.getStatements()); minLineNumber = statement.getCondition().getLineNumber(); + statementCount = 2; } protected void acceptListStatement(List list) { @@ -167,7 +196,7 @@ protected void acceptListStatement(List list) { switch (size) { case 0: - minLineNumber = maxLineNumber = Integer.MAX_VALUE; + minLineNumber = maxLineNumber = 0; break; case 1: list.get(0).accept(this); @@ -180,18 +209,20 @@ protected void acceptListStatement(List list) { list.get(size - 1).accept(this); minLineNumber = min; + statementCount = size; break; } } protected void safeAcceptListStatement(List list) { if (list == null) { - minLineNumber = maxLineNumber = Integer.MAX_VALUE; + minLineNumber = maxLineNumber = 0; } else { acceptListStatement(list); } } + // -- Expression -- // @Override public void visit(ConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); @@ -249,7 +280,7 @@ public void visit(NewExpression expression) { parameters.accept(this); } } else { - maxLineNumber = Integer.MAX_VALUE; + maxLineNumber = expression.getLineNumber() + 1; } } @@ -262,7 +293,7 @@ protected void acceptListExpression(List list) { int size = list.size(); if (size == 0) { - maxLineNumber = Integer.MAX_VALUE; + maxLineNumber = 0; } else { list.get(size - 1).accept(this); } From 179984e20f19218ccd3a202e094dd2bbb38ceed6 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 26 May 2019 10:36:10 +0200 Subject: [PATCH 014/211] Replace bridge methods --- .../declaration/EnumDeclaration.java | 4 + .../expression/ArrayExpression.java | 4 + .../expression/InstanceOfExpression.java | 4 + .../LambdaFormalParametersExpression.java | 4 + .../expression/LengthExpression.java | 4 + .../expression/MethodReferenceExpression.java | 4 + .../model/javasyntax/expression/NewArray.java | 4 + .../expression/NewInnerExpression.java | 4 + .../expression/ParenthesesExpression.java | 4 + .../expression/PostOperatorExpression.java | 4 + .../expression/PreOperatorExpression.java | 4 + .../reference/ExpressionElementValue.java | 4 + .../statement/ForEachStatement.java | 4 + .../javasyntax/statement/ForStatement.java | 4 + .../statement/LambdaExpressionStatement.java | 4 + .../statement/SynchronizedStatement.java | 4 + .../javasyntax/statement/ThrowStatement.java | 4 + .../javasyntax/statement/TryStatement.java | 4 + .../AbstractUpdateExpressionVisitor.java | 394 ++++++++++++++++++ .../visitor/CreateInstructionsVisitor.java | 11 +- .../visitor/UpdateBridgeMethodVisitor.java | 337 +++++++++++++++ .../visitor/UpdateJavaSyntaxTreeVisitor.java | 14 +- 22 files changed, 822 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java index 2e856d5b..07bf9d1b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java @@ -111,6 +111,10 @@ public BaseExpression getArguments() { return arguments; } + public void setArguments(BaseExpression arguments) { + this.arguments = arguments; + } + public BodyDeclaration getBodyDeclaration() { return bodyDeclaration; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java index a5a9dd61..ed1ff288 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java @@ -29,6 +29,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + public Expression getIndex() { return index; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java index 1c9333c9..1c34d42f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java @@ -30,6 +30,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + public Type getInstanceOfType() { return instanceOfType; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java index bf0e68f5..4e0011ca 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java @@ -28,6 +28,10 @@ public BaseFormalParameter getParameters() { return parameters; } + public void setParameters(BaseFormalParameter parameters) { + this.parameters = parameters; + } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java index 122d89a9..2e4678f9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java @@ -31,6 +31,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java index ee512aee..4b135e45 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java @@ -35,6 +35,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + public String getInternalTypeName() { return internalTypeName; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java index 948f01ba..5dc77364 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java @@ -21,6 +21,10 @@ public BaseExpression getDimensionExpressionList() { return dimensionExpressionList; } + public void setDimensionExpressionList(BaseExpression dimensionExpressionList) { + this.dimensionExpressionList = dimensionExpressionList; + } + @Override public int getPriority() { return 3; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java index cc65bff8..f4d18589 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java @@ -23,6 +23,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public int getPriority() { return 3; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java index 0724b7d3..02411ce4 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java @@ -26,6 +26,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java index 2c2a0dcd..1b3e1083 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java @@ -32,6 +32,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public Type getType() { return expression.getType(); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java index 1c3d7fb0..530cac20 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java @@ -32,6 +32,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public Type getType() { return expression.getType(); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java index a0463726..d728819f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ExpressionElementValue.java @@ -20,6 +20,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public void accept(ReferenceVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java index dc34de90..63bc28db 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java @@ -35,6 +35,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + public BaseStatement getStatements() { return statements; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java index 280aacf2..ede847f9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java @@ -60,6 +60,10 @@ public BaseExpression getUpdate() { return update; } + public void setUpdate(BaseExpression update) { + this.update = update; + } + public BaseStatement getStatements() { return statements; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java index c93de4d2..ec1c382c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java @@ -20,6 +20,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/SynchronizedStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/SynchronizedStatement.java index 1fa0bce1..cdee5301 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/SynchronizedStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/SynchronizedStatement.java @@ -22,6 +22,10 @@ public Expression getMonitor() { return monitor; } + public void setMonitor(Expression monitor) { + this.monitor = monitor; + } + public BaseStatement getStatements() { return statements; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ThrowStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ThrowStatement.java index 420eb947..04a19e28 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ThrowStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ThrowStatement.java @@ -20,6 +20,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java index 4b4bd7fc..d6b574f8 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java @@ -80,6 +80,10 @@ public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java new file mode 100644 index 00000000..5ac28971 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.declaration.*; +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.reference.*; +import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.util.DefaultList; + +public abstract class AbstractUpdateExpressionVisitor extends AbstractJavaSyntaxVisitor { + protected abstract Expression updateExpression(Expression expression); + + protected BaseExpression updateBaseExpression(BaseExpression baseExpression) { + if (baseExpression == null) { + return null; + } + + if (baseExpression.isList()) { + DefaultList list = baseExpression.getList(); + for (int length=list.size(), i=0; i bridge method + method.setFlags(method.getFlags() | FLAG_BRIDGE); + method.accept(this); + } } else if (method.getParameterTypes() != null) { for (Type type : method.getParameterTypes()) { if (type.isObject() && ((ObjectType)type).getName() == null) { @@ -60,8 +66,9 @@ public void visit(BodyDeclaration declaration) { } } } + for (ClassFileConstructorOrMethodDeclaration method : methods) { - if ((method.getFlags() & FLAG_SYNTHETIC) == 0) { + if ((method.getFlags() & (FLAG_SYNTHETIC|FLAG_BRIDGE)) == 0) { method.accept(this); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java new file mode 100644 index 00000000..761d72e2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.declaration.*; +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMethodDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.util.DefaultList; + +import java.util.HashMap; +import java.util.List; + +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.*; + +public class UpdateBridgeMethodVisitor extends AbstractUpdateExpressionVisitor { + protected BodyDeclarationsVisitor bodyDeclarationsVisitor = new BodyDeclarationsVisitor(); + protected HashMap> bridgeMethodDeclarations = new HashMap<>(); + + public boolean init(ClassFileBodyDeclaration bodyDeclaration) { + bridgeMethodDeclarations.clear(); + bodyDeclarationsVisitor.visit(bodyDeclaration); + return !bridgeMethodDeclarations.isEmpty(); + } + + @SuppressWarnings("unchecked") + protected Expression updateExpression(Expression expression) { + if (expression.getClass() != MethodInvocationExpression.class) { + return expression; + } + + MethodInvocationExpression mie1 = (MethodInvocationExpression)expression; + HashMap map = bridgeMethodDeclarations.get(mie1.getExpression().getType().getDescriptor()); + + if (map == null) { + return expression; + } + + ClassFileMethodDeclaration methodBridgeDeclaration = map.get(mie1.getName() + mie1.getDescriptor()); + + if (methodBridgeDeclaration == null) { + return expression; + } + + Statement statement = methodBridgeDeclaration.getStatements().getFirst(); + Class statementClass = statement.getClass(); + Expression exp; + + if (statementClass == ReturnExpressionStatement.class) { + exp = ((ReturnExpressionStatement) statement).getExpression(); + } else if (statement.getClass() == ExpressionStatement.class) { + exp = ((ExpressionStatement) statement).getExpression(); + } else { + return expression; + } + + Class expClass = exp.getClass(); + int parameterTypesCount = methodBridgeDeclaration.getParameterTypes().size(); + + if (expClass == FieldReferenceExpression.class) { + FieldReferenceExpression fre = (FieldReferenceExpression) exp; + + expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); + + return new FieldReferenceExpression(mie1.getLineNumber(), mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()); + } else if (expClass == MethodInvocationExpression.class) { + MethodInvocationExpression mie2 = (MethodInvocationExpression) exp; + + if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { + return new MethodInvocationExpression(mie1.getLineNumber(), mie2.getType(), mie2.getExpression(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), mie1.getParameters()); + } else { + BaseExpression newParameters = null; + BaseExpression mie1Parameters = mie1.getParameters(); + + if (mie1Parameters != null) { + switch (mie1Parameters.size()) { + case 0: + case 1: + break; + case 2: + newParameters = mie1Parameters.getList().get(1); + break; + default: + DefaultList list = mie1Parameters.getList(); + newParameters = new Expressions(list.subList(1, list.size())); + break; + } + } + + return new MethodInvocationExpression(mie1.getLineNumber(), mie2.getType(), mie1Parameters.getFirst(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameters); + } + } else if (expClass == BinaryOperatorExpression.class) { + BinaryOperatorExpression boe = (BinaryOperatorExpression) exp; + FieldReferenceExpression fre = (FieldReferenceExpression) boe.getLeftExpression(); + + if (parameterTypesCount == 1) { + return new BinaryOperatorExpression( + mie1.getLineNumber(), mie1.getType(), + new FieldReferenceExpression(fre.getType(), fre.getExpression(), fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()), + boe.getOperator(), + mie1.getParameters().getFirst(), + boe.getPriority()); + } else if (parameterTypesCount == 2) { + DefaultList parameters = mie1.getParameters().getList(); + + return new BinaryOperatorExpression( + mie1.getLineNumber(), mie1.getType(), + new FieldReferenceExpression(fre.getType(), parameters.get(0), fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()), + boe.getOperator(), + parameters.get(1), + boe.getPriority()); + } + } else if (expClass == PostOperatorExpression.class) { + PostOperatorExpression poe = (PostOperatorExpression)exp; + FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); + + expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); + + return new PostOperatorExpression( + mie1.getLineNumber(), + new FieldReferenceExpression(mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()), + poe.getOperator()); + } else if (expClass == PreOperatorExpression.class) { + PreOperatorExpression poe = (PreOperatorExpression)exp; + FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); + + expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); + + return new PreOperatorExpression( + mie1.getLineNumber(), + poe.getOperator(), + new FieldReferenceExpression(mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor())); + } else if (expClass == IntegerConstantExpression.class) { + return exp; + } + + return expression; + } + + protected class BodyDeclarationsVisitor extends AbstractJavaSyntaxVisitor { + protected HashMap map = null; + + @Override + public void visit(BodyDeclaration declaration) { + ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; + List methodDeclarations = bodyDeclaration.getMethodDeclarations(); + + if ((methodDeclarations != null) && !methodDeclarations.isEmpty()) { + HashMap backup = map; + + map = new HashMap<>(); + + acceptListDeclaration(methodDeclarations); + + if (!map.isEmpty()) { + bridgeMethodDeclarations.put('L' + bodyDeclaration.getInternalTypeName() + ';', map); + } + + map = backup; + } + + safeAcceptListDeclaration(bodyDeclaration.getInnerTypeDeclarations()); + } + + @Override + public void visit(MethodDeclaration declaration) { + if ((declaration.getFlags() & FLAG_STATIC) == 0) { + return; + } + + BaseStatement statements = declaration.getStatements(); + + if ((statements == null) || (statements.size() != 1)) { + return; + } + + String name = declaration.getName(); + + if (!name.startsWith("access$")) { + return; + } + + ClassFileMethodDeclaration bridgeMethodDeclaration = (ClassFileMethodDeclaration)declaration; + + if (!checkBridgeMethodDeclaration(bridgeMethodDeclaration)) { + return; + } + + map.put(name + declaration.getDescriptor(), bridgeMethodDeclaration); + } + + @Override public void visit(ClassDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); } + @Override public void visit(EnumDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); } + @Override public void visit(InterfaceDeclaration declaration) {} + @Override public void visit(AnnotationDeclaration declaration) {} + + private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMethodDeclaration) { + Statement statement = bridgeMethodDeclaration.getStatements().getFirst(); + Class statementClass = statement.getClass(); + Expression exp; + + if (statementClass == ReturnExpressionStatement.class) { + exp = ((ReturnExpressionStatement) statement).getExpression(); + } else if (statement.getClass() == ExpressionStatement.class) { + exp = ((ExpressionStatement) statement).getExpression(); + } else { + return false; + } + + Class expClass = exp.getClass(); + int parameterTypesCount = bridgeMethodDeclaration.getParameterTypes().size(); + + if (expClass == FieldReferenceExpression.class) { + FieldReferenceExpression fre = (FieldReferenceExpression) exp; + + if (parameterTypesCount == 0) { + return (fre.getExpression() != null) && (fre.getExpression().getClass() == ObjectTypeReferenceExpression.class); + } else if (parameterTypesCount == 1) { + return (fre.getExpression() == null) || checkLocalVariableReference(fre.getExpression(), 0); + } + } else if (expClass == MethodInvocationExpression.class) { + MethodInvocationExpression mie2 = (MethodInvocationExpression) exp; + + if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { + BaseExpression mie2Parameters = mie2.getParameters(); + + if ((mie2Parameters == null) || (mie2Parameters.size() == 0)) { + return true; + } + + if (mie2Parameters.isList()) { + int i = 0; + for (Expression parameter : mie2Parameters.getList()) { + if (!checkLocalVariableReference(parameter, i++)) { + return false; + } + Type type = parameter.getType(); + if (type.equals(PrimitiveType.TYPE_LONG) || type.equals(PrimitiveType.TYPE_DOUBLE)) { + i++; + } + } + return true; + } + + return checkLocalVariableReference(mie2Parameters, 0); + } else if ((parameterTypesCount > 0) && checkLocalVariableReference(mie2.getExpression(), 0)) { + BaseExpression mie2Parameters = mie2.getParameters(); + + if ((mie2Parameters == null) || (mie2Parameters.size() == 0)) { + return true; + } + + if (mie2Parameters.isList()) { + int i = 1; + for (Expression parameter : mie2Parameters.getList()) { + if (!checkLocalVariableReference(parameter, i++)) { + return false; + } + Type type = parameter.getType(); + if (type.equals(PrimitiveType.TYPE_LONG) || type.equals(PrimitiveType.TYPE_DOUBLE)) { + i++; + } + } + return true; + } + + return checkLocalVariableReference(mie2Parameters, 1); + } + } else if (expClass == BinaryOperatorExpression.class) { + BinaryOperatorExpression boe = (BinaryOperatorExpression) exp; + + if (parameterTypesCount == 1) { + if ((boe.getLeftExpression().getClass() == FieldReferenceExpression.class) && checkLocalVariableReference(boe.getRightExpression(), 0)) { + FieldReferenceExpression fre = (FieldReferenceExpression) boe.getLeftExpression(); + + return (fre.getExpression().getClass() == ObjectTypeReferenceExpression.class); + } + } else if (parameterTypesCount == 2) { + if ((boe.getLeftExpression().getClass() == FieldReferenceExpression.class) && checkLocalVariableReference(boe.getRightExpression(), 1)) { + FieldReferenceExpression fre = (FieldReferenceExpression) boe.getLeftExpression(); + + return checkLocalVariableReference(fre.getExpression(), 0); + } + } + } else if (expClass == PostOperatorExpression.class) { + PostOperatorExpression poe = (PostOperatorExpression)exp; + + if (poe.getExpression().getClass() == FieldReferenceExpression.class) { + FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); + + if ((parameterTypesCount == 0) && (fre.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { + return true; + } else if ((parameterTypesCount == 1) && (fre.getExpression() != null) && checkLocalVariableReference(fre.getExpression(), 0)) { + return true; + } + } + } else if ((parameterTypesCount == 1) && (expClass == PreOperatorExpression.class)) { + PreOperatorExpression poe = (PreOperatorExpression)exp; + + if (poe.getExpression().getClass() == FieldReferenceExpression.class) { + FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); + + if ((parameterTypesCount == 0) && (fre.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { + return true; + } else if ((parameterTypesCount == 1) && (fre.getExpression() != null) && checkLocalVariableReference(fre.getExpression(), 0)) { + return true; + } + } + } else if ((parameterTypesCount == 0) && (expClass == IntegerConstantExpression.class)) { + return true; + } + + return false; + } + + private boolean checkLocalVariableReference(BaseExpression expression, int index) { + if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { + return false; + } + + ClassFileLocalVariableReferenceExpression var = (ClassFileLocalVariableReferenceExpression) expression; + + return (var.getLocalVariable().getIndex() == index); + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java index ba7ab19f..02d4eb95 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java @@ -16,13 +16,14 @@ public class UpdateJavaSyntaxTreeVisitor extends AbstractJavaSyntaxVisitor { - protected static AggregateFieldsVisitor aggregateFieldsVisitor = new AggregateFieldsVisitor(); - protected static SortMembersVisitor sortMembersVisitor = new SortMembersVisitor(); + protected static final AggregateFieldsVisitor AGGREGATE_FIELDS_VISITOR = new AggregateFieldsVisitor(); + protected static final SortMembersVisitor SORT_MEMBERS_VISITOR = new SortMembersVisitor(); protected InitInnerClassVisitor initInnerClassVisitor = new InitInnerClassVisitor(); protected InitStaticFieldVisitor initStaticFieldVisitor = new InitStaticFieldVisitor(); protected InitInstanceFieldVisitor initInstanceFieldVisitor = new InitInstanceFieldVisitor(); protected InitEnumVisitor initEnumVisitor = new InitEnumVisitor(); + protected UpdateBridgeMethodVisitor replaceBridgeMethodVisitor = new UpdateBridgeMethodVisitor(); protected CreateInstructionsVisitor createInstructionsVisitor; protected RemoveDefaultConstructorVisitor removeDefaultConstructorVisitor; @@ -60,8 +61,13 @@ public void visit(BodyDeclaration declaration) { initStaticFieldVisitor.visit(declaration); initInstanceFieldVisitor.visit(declaration); removeDefaultConstructorVisitor.visit(declaration); - aggregateFieldsVisitor.visit(declaration); - sortMembersVisitor.visit(declaration); + AGGREGATE_FIELDS_VISITOR.visit(declaration); + SORT_MEMBERS_VISITOR.visit(declaration); + + if ((bodyDeclaration.getOuterBodyDeclaration() == null) && (bodyDeclaration.getInnerTypeDeclarations() != null) && replaceBridgeMethodVisitor.init(bodyDeclaration)) { + // Replace bridge method invocation + replaceBridgeMethodVisitor.visit(bodyDeclaration); + } } @Override From f831a964905519b471febcc89093c68bc405130e Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 26 May 2019 10:36:52 +0200 Subject: [PATCH 015/211] Cleanup --- .../util/ByteCodeParser.java | 4 +- .../util/StatementMaker.java | 2 +- .../visitor/CompilationUnitVisitor.java | 38 ++++++++++--------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 321f9b5a..832e9e78 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -760,7 +760,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } if (TYPE_VOID.equals(returnedType)) { if ((opcode == 183) && // INVOKESPECIAL - "".equals(name)) { + "".equals(name)) { if (expression1.getClass() == NewExpression.class) { ((NewExpression) expression1).setParameters(parameters); @@ -774,7 +774,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } } else { if ((opcode == 182) && // INVOKEVIRTUAL - "toString".equals(name) && "()Ljava/lang/String;".equals(descriptor)) { + "toString".equals(name) && "()Ljava/lang/String;".equals(descriptor)) { typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); if ("java/lang/StringBuilder".equals(typeName) || "java/lang/StringBuffer".equals(typeName)) { stack.push(CreateConcatStringUtil.create(expression1, lineNumber, typeName)); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 5002ea51..e5da834e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -107,7 +107,7 @@ public Statements make(ControlFlowGraph cfg) { localVariableMaker.popFrame(); - // Update integer constant type to 'byte', 'char', 'short', 'int' + // Update integer constant type to 'byte', 'char', 'short' or 'int' statements.accept(updateIntegerConstantTypeVisitor); // Change ++i; with i++; diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 85dfe57b..3a1d596f 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -24,6 +24,8 @@ import java.util.Iterator; import java.util.List; +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.*; + public class CompilationUnitVisitor extends StatementVisitor { public static final KeywordToken ABSTRACT = new KeywordToken("abstract"); public static final KeywordToken ANNOTATION = new KeywordToken("@interface"); @@ -54,10 +56,10 @@ public CompilationUnitVisitor(Loader loader, String mainInternalTypeName, Import @Override public void visit(AnnotationDeclaration declaration) { - if ((declaration.getFlags() & (Declaration.FLAG_SYNTHETIC | Declaration.FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); - buildFragmentsForTypeDeclaration(declaration, declaration.getFlags() & ~Declaration.FLAG_ABSTRACT, ANNOTATION); + buildFragmentsForTypeDeclaration(declaration, declaration.getFlags() & ~FLAG_ABSTRACT, ANNOTATION); fragments.addTokensFragment(tokens); @@ -207,7 +209,7 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(ClassDeclaration declaration) { - if ((declaration.getFlags() & (Declaration.FLAG_SYNTHETIC | Declaration.FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); buildFragmentsForClassOrInterfaceDeclaration(declaration, declaration.getFlags(), CLASS); @@ -318,7 +320,7 @@ public void visit(CompilationUnit compilationUnit) { @Override public void visit(ConstructorDeclaration declaration) { - if ((declaration.getFlags() & (Declaration.FLAG_SYNTHETIC|Declaration.FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & (FLAG_SYNTHETIC|FLAG_BRIDGE)) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); tokens = new Tokens(); @@ -463,7 +465,7 @@ public void visit(ElementValuePair reference) { @Override public void visit(EnumDeclaration declaration) { - if ((declaration.getFlags() & (Declaration.FLAG_SYNTHETIC | Declaration.FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); buildFragmentsForTypeDeclaration(declaration, declaration.getFlags(), ENUM); @@ -605,7 +607,7 @@ public void visit(ExpressionVariableInitializer declaration) { @Override public void visit(FieldDeclaration declaration) { - if ((declaration.getFlags() & (Declaration.FLAG_SYNTHETIC | Declaration.FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); tokens = new Tokens(); @@ -755,10 +757,10 @@ public void visit(InstanceInitializerDeclaration declaration) { @Override public void visit(InterfaceDeclaration declaration) { - if ((declaration.getFlags() & (Declaration.FLAG_SYNTHETIC | Declaration.FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); - buildFragmentsForClassOrInterfaceDeclaration(declaration, declaration.getFlags() & ~Declaration.FLAG_ABSTRACT, INTERFACE); + buildFragmentsForClassOrInterfaceDeclaration(declaration, declaration.getFlags() & ~FLAG_ABSTRACT, INTERFACE); tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); @@ -882,7 +884,7 @@ public void visit(MemberDeclarations list) { @Override public void visit(MethodDeclaration declaration) { - if ((declaration.getFlags() & (Declaration.FLAG_SYNTHETIC | Declaration.FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); tokens = new Tokens(); @@ -1083,41 +1085,41 @@ protected void buildFragmentsForClassOrInterfaceDeclaration(InterfaceDeclaration } protected void buildTokensForAccessFlags(int flags) { - if ((flags & Declaration.FLAG_PUBLIC) != 0) { + if ((flags & FLAG_PUBLIC) != 0) { tokens.add(PUBLIC); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_PRIVATE) != 0) { + if ((flags & FLAG_PRIVATE) != 0) { tokens.add(PRIVATE); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_PROTECTED) != 0) { + if ((flags & FLAG_PROTECTED) != 0) { tokens.add(PROTECTED); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_STATIC) != 0) { + if ((flags & FLAG_STATIC) != 0) { tokens.add(STATIC); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_FINAL) != 0) { + if ((flags & FLAG_FINAL) != 0) { tokens.add(FINAL); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_NATIVE) != 0) { + if ((flags & FLAG_NATIVE) != 0) { tokens.add(NATIVE); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_ABSTRACT) != 0) { + if ((flags & FLAG_ABSTRACT) != 0) { tokens.add(ABSTRACT); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_BRIDGE) != 0) { + if ((flags & FLAG_BRIDGE) != 0) { tokens.add(StartMarkerToken.COMMENT); tokens.add(COMMENT_BRIDGE); tokens.add(EndMarkerToken.COMMENT); tokens.add(TextToken.SPACE); } - if ((flags & Declaration.FLAG_SYNTHETIC) != 0) { + if ((flags & FLAG_SYNTHETIC) != 0) { tokens.add(StartMarkerToken.COMMENT); tokens.add(COMMENT_SYNTHETIC); tokens.add(EndMarkerToken.COMMENT); From 651c0a7d7ffe8499764c4341f4ea3bc3328e8dfe Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 26 May 2019 10:39:16 +0200 Subject: [PATCH 016/211] Update version to 1.0.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9607ea65..9f4ad34f 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.0.1' +version='1.0.2' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From 5f7312e6b9e816828de833440da01dbf16cb0556 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 30 May 2019 13:23:09 +0200 Subject: [PATCH 017/211] Update README.md --- README.md | 8 ++++++++ src/website/img/btn_donate_euro.gif | Bin 0 -> 1518 bytes src/website/img/btn_donate_usd.gif | Bin 0 -> 1537 bytes 3 files changed, 8 insertions(+) create mode 100644 src/website/img/btn_donate_euro.gif create mode 100644 src/website/img/btn_donate_usd.gif diff --git a/README.md b/README.md index 2ead373a..b36e863f 100644 --- a/README.md +++ b/README.md @@ -109,3 +109,11 @@ decompiler.decompile(loader, printer, "path/to/YourClass"); String source = printer.toString(); ``` + +## License +Released under the [GNU GPL v3](LICENSE). + +## Donations +Did JD-GUI help you to solve a critical situation? Do you use JD-Eclipse daily? What about making a donation? + +[![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_euro.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=C88ZMVZ78RF22) [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_usd.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CRMXT4Y4QLQGU) diff --git a/src/website/img/btn_donate_euro.gif b/src/website/img/btn_donate_euro.gif new file mode 100644 index 0000000000000000000000000000000000000000..f317055f02a7bbc7cd9b0dada33595b829ec9685 GIT binary patch literal 1518 zcmd6m`#X~h0LR~5ZF3tlhB;?b5oWf%yS(JG&BW%CWGA9rBJ`X}C{LHCNJ^z5jX zBI)E9&bqj6Ox1Aq`kBHi=XoV>tquC5;KFK`?@#$~hdUmNL;%2#VNi%r z3F+ex)hW`pJC~+f(WAfff(G_9{9FSU?%naB4urd9+Tp}`C0{NgQH(K5?UK(* zX!;=-?Mv3dAbLw3>E=38h`81ru-Xc3qT;Y<1ZyJ!p1eRNqP3cR>mA~yX2D9k$b)6@ z_=?^4=R3oVx+<;ImCRMtI_919;|YiYviqKV!u4*8R?^B5HZHjl($*; zeI55*E!WvWZ=j4>d*1fxRXe!L$CasnY`5h?v-_7OPcNP!K?iw!x8)%@Ws9T!(Onko zO@zOySX45$Fohl^BQHGTzpCcMZ!>dY=rQQ{MYaEI18=981iw6%5o1++#QN5W4ex3> z%FA}=<9;$RL@&0w&o*#J?>Mcr2>!0;-aNixu95$)7JO08JQ-nWPQr8)GQKuR7S#c- zAFx+d9w+u#stO#Q<=DG1^+jw0Z@!^+Fv3t5rHezRMN`ozKy#D%>OQBtgpqrQw%+cX zf0+JHv&VLKWB9o!=O7L4mcpZ{ud3OO)`aG3_P>Zp@9V&y&9Fy8EuLJl(`sT5?4ZQ@ zn-1T0f=7?SW5>IS855N(c=93u0I=E_{{KPO8hIwgMy15Y&{7jp;%VMe|3HAgj7AUu z7-0Ok4g41hfYSmnp1Ne{Wu+Sj=uygv01#(L7pM5Jfi%F>ksnTp1UfGnm@`xOt>)c% z0~S+5nP%57y{?zFH>bXRYB~S{#uYYuHG$K0L%BNfGd-7Ar@HdfZ_8Y7^#18IYJ3qro$gy8 zRO}O+O8H{BaIHoG_*q#CyNpM48nwK(sDf5Bv*lbOt7GgA79XcLnLC^waIG3Dc^j%3 zPm{*>`xNC%Vlv8NZI*FHGYBFn4zaS7CPZFWcoIwS(wL-xN4#vRL_WMfa2#_hNgG~u zfCJpchqxSGsz;rn&EZPq?9PlV1?}M&u_Up#IA71`?3*mmO_D}1_cTEjpw9C)XUfgq zrgh5EWBY=r{au=^pc|Cu3+6zi*NB0tp={)U@J%-I6s3GRA#g6T6|rAAB??v^i5|7N zq!E{aR+L(Az&DY27A)t^T*&Ir@ezS~P=yrRFG;)&vP$YD8U2($XoddbcnoUKT9Fs% z0nJFjFepO=US)mUn4ctxMB(`1#TU_tqPJ@FUT8{4-(HM}4lN3fY{%Vb3L=nQg^Agq ziks0zZmYG?O^21xz5NkmeL(%-8B|bPd z1dPb1BZC`$)%anXi@4F1fy^l}=sxyB4>yn{{G?y1Opt(cHKNU)KreKpC3U|QEo#;M-N$zu1^@$0# JR5B6R@-Iak)QtcD literal 0 HcmV?d00001 diff --git a/src/website/img/btn_donate_usd.gif b/src/website/img/btn_donate_usd.gif new file mode 100644 index 0000000000000000000000000000000000000000..3682dea12a4def16bb135e8a52b3c23c8449cf3f GIT binary patch literal 1537 zcmd6m{Xf$Q0LQ<3z{Vau4pW=qs9`gkO~uAM&14?tA&Pm(>UCX;QgRnvl#cR{E1im5 zo>C{`wH{~>h%lo_&a0$)aYe_KJnwtme{t{E>+{q5m(MS6zW`r0M0s!Bp1A|2K zjsE(kx_Me9ry|3eM9|~XF&KRq3<@l@yIEW4f#av%G`fHq$yg2T^8+T!0kzf_HPhlY zUPlAfF%xz44JG^aEtiS9ZF!HIkm99*l}yV2#f+~KyWleWtWk6k{-E_Md9_n4)rq*b}wom@NZpyb6(TG?T8 ze}&`fW45KS?s})^NeM9{#$u$}IW5XOcsu@68xvHy&$Tf(G|3D1nRqlzz{VvBO_}xv z)6K5$n_M|tQR-_>O=rG)c)vBP7b-P?zW)z^b&?zTKACTw#=AKhg^ zx7Gi%jz%=my_8Ot2uv0qv0gQ}NQ2GXsVFKLxzrgn+scgeG6G*5|2fI3{D^hc3CjB> z7g?dhnUqb&Soo6MW46_G^mpgg$8I0*xn9qt%(b!JH!+4PowDLA&5d-rE>Zt!=Pz~c ze0__)rt&8_wY9QE)7?r<^)oO9Lm)0RRAYa=`x|WG&wNaIz#lIf<09FI`IV3kVVcUBx7)yfp#TUi03wOYSRX5c6aYo2!~sAGmh6@8PY1FAQ%6=TAs*=d1!L}%&XSw= zmZ~i#hjUL=_T_Mkq%Rk%5G}v4(>_e}w$uh+^YI|XR*j&z)@P}>a*|(;o zB`Jy&m|Yo@A_+AtMrZz7{*J;g(Bld#bY|YdpvWjSh9|YNDemR8kJ1j~7DE|PcW-N* z5M^(b2TCFKLGs~zRjm~ce#lSLc#gh_U!k+FD^GJeM(tnBgG<;`LM*=0s~gwFPtL>F zoek*`o4w2K7Q-j^h7t#QG`@@-?9xC+5!?GUL|r#r09A9}6hMC>OeX9X&Bekif7H)u3Q%X$g;kZ=69D+BsHTPVg0q z6&Pcg#8PY)rN}n(-8EWb`karg_%ZGXOORFrvK$4e zg+JoWc>1oyXLCehywdZajYym@kQI`L5REkR80O0f!}$$+?q?eeEXVsXNNkE%qg!f8 zEq>tpRKIYbKO_%dDi?{Na)fb!L0Y{iC;D Date: Thu, 30 May 2019 13:36:12 +0200 Subject: [PATCH 018/211] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b36e863f..9926ff06 100644 --- a/README.md +++ b/README.md @@ -116,4 +116,4 @@ Released under the [GNU GPL v3](LICENSE). ## Donations Did JD-GUI help you to solve a critical situation? Do you use JD-Eclipse daily? What about making a donation? -[![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_euro.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=C88ZMVZ78RF22) [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-gui/master/src/website/img/btn_donate_usd.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CRMXT4Y4QLQGU) +[![paypal](https://raw.githubusercontent.com/java-decompiler/jd-core/master/src/website/img/btn_donate_euro.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=C88ZMVZ78RF22) [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-core/master/src/website/img/btn_donate_usd.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CRMXT4Y4QLQGU) From 9943bc90b932dc7d5fba2ff84f4b5767f08a035d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 31 May 2019 10:14:04 +0200 Subject: [PATCH 019/211] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9926ff06..be60eab2 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,16 @@ JD-Core is a JAVA decompiler written in JAVA. -- Java Decompiler projects home page: +- Java Decompiler project home page: [http://java-decompiler.github.io](http://java-decompiler.github.io) -- JD-GUI source code: +- JD-Core source code: [https://github.com/java-decompiler/jd-core](https://github.com/java-decompiler/jd-core) - Maven repository: [https://raw.github.com/java-decompiler/mvn-repo/master](https://raw.github.com/java-decompiler/mvn-repo/master) ## Description JD-Core is a standalone JAVA library containing the JAVA decompiler of -"Java Decompiler project". It support Java 1.1.8 to Java 10.0, +"Java Decompiler project". It support Java 1.1.8 to Java 12.0, including Lambda expressions, method references and default methods. JD-Core is the engine of JD-GUI. From 4e1300e62cd4e067dcbae400b91f2da0288e289b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 31 May 2019 10:17:16 +0200 Subject: [PATCH 020/211] Prepare version 1.0.3 --- build.gradle | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 9f4ad34f..b2f5c0be 100644 --- a/build.gradle +++ b/build.gradle @@ -6,28 +6,28 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.0.2' +version='1.0.3' tasks.withType(JavaCompile) { - sourceCompatibility = targetCompatibility = '1.8' - options.compilerArgs << '-Xlint:deprecation' - options.compilerArgs << '-Xlint:unchecked' - options.encoding = 'UTF-8' + sourceCompatibility = targetCompatibility = '1.8' + options.compilerArgs << '-Xlint:deprecation' + options.compilerArgs << '-Xlint:unchecked' + options.encoding = 'UTF-8' } repositories { - mavenCentral() + mavenCentral() } jar { - manifest { - attributes 'JD-Core-Version': version - } + manifest { + attributes 'JD-Core-Version': version + } } // 'cleanIdea' task extension // cleanIdea.doFirst { - delete project.name + '.iws' - delete 'out' - followSymlinks = true + delete project.name + '.iws' + delete 'out' + followSymlinks = true } From 91267173c5d21f473a9467113ebc798a2640f0da Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 1 Jun 2019 18:38:57 +0200 Subject: [PATCH 021/211] Add Java 9+ module support --- .../core/v1/api/loader/LoaderException.java | 10 +- .../org/jd/core/v1/api/printer/Printer.java | 26 +-- .../jd/core/v1/model/classfile/Constants.java | 43 +++-- .../attribute/AttributeMethodParameters.java | 20 ++ .../classfile/attribute/AttributeModule.java | 64 +++++++ .../attribute/AttributeModuleMainClass.java | 22 +++ .../attribute/AttributeModulePackages.java | 20 ++ .../classfile/attribute/MethodParameter.java | 36 ++++ .../model/classfile/attribute/ModuleInfo.java | 46 +++++ .../classfile/attribute/PackageInfo.java | 46 +++++ .../classfile/attribute/ServiceInfo.java | 39 ++++ .../javasyntax/AbstractJavaSyntaxVisitor.java | 3 + .../AbstractNopDeclarationVisitor.java | 1 + .../javasyntax/declaration/Declaration.java | 39 ++-- .../declaration/DeclarationVisitor.java | 1 + .../declaration/ModuleDeclaration.java | 132 +++++++++++++ .../processor/ConvertClassFileProcessor.java | 62 ++++++ .../util/LocalVariableMaker.java | 4 +- .../util/ObjectTypeMaker.java | 4 +- .../util/StatementMaker.java | 4 +- .../classfile/ClassFileDeserializer.java | 122 +++++++++++- .../visitor/CompilationUnitVisitor.java | 178 ++++++++++++++++++ .../visitor/TypeVisitor.java | 10 + .../java/org/jd/core/v1/util/DefaultList.java | 12 +- 24 files changed, 877 insertions(+), 67 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeMethodParameters.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModule.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModuleMainClass.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModulePackages.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/MethodParameter.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ModuleInfo.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/PackageInfo.java create mode 100644 src/main/java/org/jd/core/v1/model/classfile/attribute/ServiceInfo.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java diff --git a/src/main/java/org/jd/core/v1/api/loader/LoaderException.java b/src/main/java/org/jd/core/v1/api/loader/LoaderException.java index e5fda754..58ab8fc4 100644 --- a/src/main/java/org/jd/core/v1/api/loader/LoaderException.java +++ b/src/main/java/org/jd/core/v1/api/loader/LoaderException.java @@ -9,10 +9,10 @@ public class LoaderException extends Exception { - private static final long serialVersionUID = 9506606333927794L; - public LoaderException() {} - - public LoaderException(String msg) { super(msg); } + private static final long serialVersionUID = 9506606333927794L; + public LoaderException() {} - public LoaderException(Throwable cause) { super(cause); } + public LoaderException(String msg) { super(msg); } + + public LoaderException(Throwable cause) { super(cause); } } diff --git a/src/main/java/org/jd/core/v1/api/printer/Printer.java b/src/main/java/org/jd/core/v1/api/printer/Printer.java index bf2720fb..2bd89271 100644 --- a/src/main/java/org/jd/core/v1/api/printer/Printer.java +++ b/src/main/java/org/jd/core/v1/api/printer/Printer.java @@ -9,7 +9,7 @@ public interface Printer { - int UNKNOWN_LINE_NUMBER = 0; + int UNKNOWN_LINE_NUMBER = 0; // Declaration & reference flags int TYPE_FLAG = 1; @@ -27,20 +27,20 @@ public interface Printer { void end(); void printText(String text); - void printNumericConstant(String constant); - void printStringConstant(String constant, String ownerInternalName); - void printKeyword(String keyword); + void printNumericConstant(String constant); + void printStringConstant(String constant, String ownerInternalName); + void printKeyword(String keyword); void printDeclaration(int flags, String internalTypeName, String name, String descriptor); - void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName); + void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName); - void indent(); - void unindent(); - - void startLine(int lineNumber); - void endLine(); - void extraLine(int count); + void indent(); + void unindent(); - void startMarker(int type); - void endMarker(int type); + void startLine(int lineNumber); + void endLine(); + void extraLine(int count); + + void startMarker(int type); + void endMarker(int type); } diff --git a/src/main/java/org/jd/core/v1/model/classfile/Constants.java b/src/main/java/org/jd/core/v1/model/classfile/Constants.java index 31dc4daf..1028e875 100644 --- a/src/main/java/org/jd/core/v1/model/classfile/Constants.java +++ b/src/main/java/org/jd/core/v1/model/classfile/Constants.java @@ -8,23 +8,28 @@ package org.jd.core.v1.model.classfile; public interface Constants { - // Access flag for Class, Field, Method, Nested class - short ACC_PUBLIC = 0x0001; // C F M N - short ACC_PRIVATE = 0x0002; // F M N - short ACC_PROTECTED = 0x0004; // F M N - short ACC_STATIC = 0x0008; // C F M N - short ACC_FINAL = 0x0010; // C F M N - short ACC_SYNCHRONIZED = 0x0020; // M - short ACC_SUPER = 0x0020; // C - short ACC_VOLATILE = 0x0040; // F - short ACC_BRIDGE = 0x0040; // M - short ACC_TRANSIENT = 0x0080; // F - short ACC_VARARGS = 0x0080; // M - short ACC_NATIVE = 0x0100; // M - short ACC_INTERFACE = 0x0200; // C N - short ACC_ABSTRACT = 0x0400; // C M N - short ACC_STRICT = 0x0800; // M - short ACC_SYNTHETIC = 0x1000; // C F M N - short ACC_ANNOTATION = 0x2000; // C N - short ACC_ENUM = 0x4000; // C F N + // Access flags for Class, Field, Method, Nested class, Module, Module Requires, Module Exports, Module Opens + int ACC_PUBLIC = 0x0001; // C F M N . . . . + int ACC_PRIVATE = 0x0002; // . F M N . . . . + int ACC_PROTECTED = 0x0004; // . F M N . . . . + int ACC_STATIC = 0x0008; // C F M N . . . . + int ACC_FINAL = 0x0010; // C F M N . . . . + int ACC_SYNCHRONIZED = 0x0020; // . . M . . . . . + int ACC_SUPER = 0x0020; // C . . . . . . . + int ACC_OPEN = 0x0020; // . . . . Mo . . . + int ACC_TRANSITIVE = 0x0020; // . . . . . MR . . + int ACC_VOLATILE = 0x0040; // . F . . . . . . + int ACC_BRIDGE = 0x0040; // . . M . . . . . + int ACC_STATIC_PHASE = 0x0040; // . . M . . MR . . + int ACC_TRANSIENT = 0x0080; // . F . . . . . . + int ACC_VARARGS = 0x0080; // . . M . . . . . + int ACC_NATIVE = 0x0100; // . . M . . . . . + int ACC_INTERFACE = 0x0200; // C . . N . . . . + int ACC_ABSTRACT = 0x0400; // C . M N . . . . + int ACC_STRICT = 0x0800; // . . M . . . . . + int ACC_SYNTHETIC = 0x1000; // C F M N Mo MR ME MO + int ACC_ANNOTATION = 0x2000; // C . . N . . . . + int ACC_ENUM = 0x4000; // C F . N . . . . + int ACC_MODULE = 0x8000; // C . . . . . . . + int ACC_MANDATED = 0x8000; // . . . . Mo MR ME MO } diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeMethodParameters.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeMethodParameters.java new file mode 100644 index 00000000..c4814353 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeMethodParameters.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeMethodParameters implements Attribute { + protected MethodParameter[] parameters; + + public AttributeMethodParameters(MethodParameter[] parameters) { + this.parameters = parameters; + } + + public MethodParameter[] getParameters() { + return parameters; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModule.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModule.java new file mode 100644 index 00000000..7d6ece94 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModule.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +// Example: https://github.com/netroby/jdk9-dev/blob/master/jdk/src/java.management/share/classes/module-info.java +public class AttributeModule implements Attribute { + protected String name; + protected int flags; + protected String version; + + protected ModuleInfo[] requires; + protected PackageInfo[] exports; + protected PackageInfo[] opens; + protected String[] uses; + protected ServiceInfo[] provides; + + public AttributeModule(String name, int flags, String version, ModuleInfo[] requires, PackageInfo[] exports, PackageInfo[] opens, String[] uses, ServiceInfo[] provides) { + this.name = name; + this.flags = flags; + this.version = version; + this.requires = requires; + this.exports = exports; + this.opens = opens; + this.uses = uses; + this.provides = provides; + } + + public String getName() { + return name; + } + + public int getFlags() { + return flags; + } + + public String getVersion() { + return version; + } + + public ModuleInfo[] getRequires() { + return requires; + } + + public PackageInfo[] getExports() { + return exports; + } + + public PackageInfo[] getOpens() { + return opens; + } + + public String[] getUses() { + return uses; + } + + public ServiceInfo[] getProvides() { + return provides; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModuleMainClass.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModuleMainClass.java new file mode 100644 index 00000000..5be61d86 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModuleMainClass.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +import org.jd.core.v1.model.classfile.constant.ConstantClass; + +public class AttributeModuleMainClass implements Attribute { + protected ConstantClass mainClass; + + public AttributeModuleMainClass(ConstantClass mainClass) { + this.mainClass = mainClass; + } + + public ConstantClass getMainClass() { + return mainClass; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModulePackages.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModulePackages.java new file mode 100644 index 00000000..9a933c45 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/AttributeModulePackages.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class AttributeModulePackages implements Attribute { + protected String[] packageNames; + + public AttributeModulePackages(String[] packageNames) { + this.packageNames = packageNames; + } + + public String[] getPackageNames() { + return packageNames; + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/MethodParameter.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/MethodParameter.java new file mode 100644 index 00000000..828cf7a2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/MethodParameter.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class MethodParameter { + protected String name; + protected int access; + + public MethodParameter(String name, int access) { + this.name = name; + this.access = access; + } + + public String getName() { + return name; + } + + public int getAccess() { + return access; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("Parameter{name=").append(name); + sb.append(", access=").append(access); + + return sb.append("}").toString(); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ModuleInfo.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ModuleInfo.java new file mode 100644 index 00000000..5d95e145 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ModuleInfo.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class ModuleInfo { + protected String name; + protected int flags; + protected String version; + + public ModuleInfo(String name, int flags, String version) { + this.name = name; + this.flags = flags; + this.version = version; + } + + public String getName() { + return name; + } + + public int getFlags() { + return flags; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("ModuleInfo{name=").append(name); + sb.append(", flags=").append(flags); + + if (version != null) { + sb.append(", version=").append(version); + } + + return sb.append("}").toString(); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/PackageInfo.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/PackageInfo.java new file mode 100644 index 00000000..8420f09b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/PackageInfo.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class PackageInfo { + protected String internalName; + protected int flags; + protected String[] moduleInfoNames; + + public PackageInfo(String internalName, int flags, String[] moduleInfoNames) { + this.internalName = internalName; + this.flags = flags; + this.moduleInfoNames = moduleInfoNames; + } + + public String getInternalName() { + return internalName; + } + + public int getFlags() { + return flags; + } + + public String[] getModuleInfoNames() { + return moduleInfoNames; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("PackageInfo{internalName=").append(internalName); + sb.append(", flags=").append(flags); + + if (moduleInfoNames != null) { + sb.append(", moduleInfoNames=").append(moduleInfoNames); + } + + return sb.append("}").toString(); + } +} diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ServiceInfo.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ServiceInfo.java new file mode 100644 index 00000000..48e19c03 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ServiceInfo.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.classfile.attribute; + +public class ServiceInfo { + protected String interfaceTypeName; + protected String[] implementationTypeNames; + + public ServiceInfo(String interfaceTypeName, String[] implementationTypeNames) { + this.interfaceTypeName = interfaceTypeName; + this.implementationTypeNames = implementationTypeNames; + } + + public String getInterfaceTypeName() { + return interfaceTypeName; + } + + public String[] getImplementationTypeNames() { + return implementationTypeNames; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("ServiceInfo{interfaceTypeName=").append(interfaceTypeName); + + if (implementationTypeNames != null) { + sb.append(", implementationTypeNames=").append(implementationTypeNames); + } + + return sb.append("}").toString(); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java index 91261fed..7d8a67b5 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java @@ -164,6 +164,9 @@ public void visit(MemberDeclarations declarations) { acceptListDeclaration(declarations); } + @Override + public void visit(ModuleDeclaration declarations) {} + @Override @SuppressWarnings("unchecked") public void visit(TypeDeclarations list) { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java index 77e159bb..e4d3f019 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AbstractNopDeclarationVisitor.java @@ -28,6 +28,7 @@ public abstract class AbstractNopDeclarationVisitor implements DeclarationVisito @Override public void visit(LocalVariableDeclarators declarators) {} @Override public void visit(MemberDeclarations declarations) {} @Override public void visit(MethodDeclaration declaration) {} + @Override public void visit(ModuleDeclaration declarations) {} @Override public void visit(StaticInitializerDeclaration declaration) {} @Override public void visit(TypeDeclarations declaration) {} } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java index 96f7def5..0e12e10d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java @@ -8,19 +8,30 @@ package org.jd.core.v1.model.javasyntax.declaration; public interface Declaration { - public final static int FLAG_PUBLIC = 0x0001; - public final static int FLAG_PRIVATE = 0x0002; - public final static int FLAG_PROTECTED = 0x0004; - public final static int FLAG_STATIC = 0x0008; - public final static int FLAG_FINAL = 0x0010; - public final static int FLAG_BRIDGE = 0x0040; - public final static int FLAG_VARARGS = 0x0080; - public final static int FLAG_NATIVE = 0x0100; - public final static int FLAG_INTERFACE = 0x0200; - public final static int FLAG_ABSTRACT = 0x0400; - public final static int FLAG_SYNTHETIC = 0x1000; - public final static int FLAG_ANNOTATION = 0x2000; - public final static int FLAG_ENUM = 0x4000; - + // Access flags for Class, Field, Method, Nested class, Module, Module Requires, Module Exports, Module Opens + int FLAG_PUBLIC = 0x0001; // C F M N . . . . + int FLAG_PRIVATE = 0x0002; // . F M N . . . . + int FLAG_PROTECTED = 0x0004; // . F M N . . . . + int FLAG_STATIC = 0x0008; // C F M N . . . . + int FLAG_FINAL = 0x0010; // C F M N . . . . + int FLAG_SYNCHRONIZED = 0x0020; // . . M . . . . . + int FLAG_SUPER = 0x0020; // C . . . . . . . + int FLAG_OPEN = 0x0020; // . . . . Mo . . . + int FLAG_TRANSITIVE = 0x0020; // . . . . . MR . . + int FLAG_VOLATILE = 0x0040; // . F . . . . . . + int FLAG_BRIDGE = 0x0040; // . . M . . . . . + int FLAG_STATIC_PHASE = 0x0040; // . . M . . MR . . + int FLAG_TRANSIENT = 0x0080; // . F . . . . . . + int FLAG_VARARGS = 0x0080; // . . M . . . . . + int FLAG_NATIVE = 0x0100; // . . M . . . . . + int FLAG_INTERFACE = 0x0200; // C . . N . . . . + int FLAG_ABSTRACT = 0x0400; // C . M N . . . . + int FLAG_STRICT = 0x0800; // . . M . . . . . + int FLAG_SYNTHETIC = 0x1000; // C F M N Mo MR ME MO + int FLAG_ANNOTATION = 0x2000; // C . . N . . . . + int FLAG_ENUM = 0x4000; // C F . N . . . . + int FLAG_MODULE = 0x8000; // C . . . . . . . + int FLAG_MANDATED = 0x8000; // . . . . Mo MR ME MO + void accept(DeclarationVisitor visitor); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java index 51da1540..90fbfa2e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/DeclarationVisitor.java @@ -28,6 +28,7 @@ public interface DeclarationVisitor { void visit(LocalVariableDeclarators declarators); void visit(MethodDeclaration declaration); void visit(MemberDeclarations declarations); + void visit(ModuleDeclaration declarations); void visit(StaticInitializerDeclaration declaration); void visit(TypeDeclarations declarations); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java new file mode 100644 index 00000000..918dd187 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.declaration; + +import java.util.List; + +public class ModuleDeclaration extends TypeDeclaration { + protected String version; + protected List requires; + protected List exports; + protected List opens; + protected List uses; + protected List provides; + + public ModuleDeclaration(int flags, String internalName, String name, String version, List requires, List exports, List opens, List uses, List provides) { + super(null, flags, internalName, name); + this.version = version; + this.requires = requires; + this.exports = exports; + this.opens = opens; + this.uses = uses; + this.provides = provides; + } + + public String getVersion() { return version; } + public List getRequires() { return requires; } + public List getExports() { return exports; } + public List getOpens() { return opens; } + public List getUses() { return uses; } + public List getProvides() { return provides; } + + @Override + public void accept(DeclarationVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "ModuleDeclaration{" + internalName + "}"; + } + + public static class ModuleInfo { + protected String name; + protected int flags; + protected String version; + + public ModuleInfo(String name, int flags, String version) { + this.name = name; + this.flags = flags; + this.version = version; + } + + public String getName() { return name; } + public int getFlags() { return flags; } + public String getVersion() { return version; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("ModuleInfo{name=").append(name); + sb.append(", flags=").append(flags); + + if (version != null) { + sb.append(", version=").append(version); + } + + return sb.append("}").toString(); + } + } + + public static class PackageInfo { + protected String internalName; + protected int flags; + protected List moduleInfoNames; + + public PackageInfo(String internalName, int flags, List moduleInfoNames) { + this.internalName = internalName; + this.flags = flags; + this.moduleInfoNames = moduleInfoNames; + } + + public String getInternalName() { return internalName; } + public int getFlags() { return flags; } + public List getModuleInfoNames() { return moduleInfoNames; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("PackageInfo{internalName=").append(internalName); + sb.append(", flags=").append(flags); + + if (moduleInfoNames != null) { + sb.append(", moduleInfoNames=").append(moduleInfoNames); + } + + return sb.append("}").toString(); + } + } + + public static class ServiceInfo { + protected String interfaceTypeName; + protected List implementationTypeNames; + + public ServiceInfo(String interfaceTypeName, List implementationTypeNames) { + this.interfaceTypeName = interfaceTypeName; + this.implementationTypeNames = implementationTypeNames; + } + + public String getInterfaceTypeName() { return interfaceTypeName; } + public List getImplementationTypeNames() { return implementationTypeNames; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("ServiceInfo{interfaceTypeName=").append(interfaceTypeName); + + if (implementationTypeNames != null) { + sb.append(", implementationTypeNames=").append(implementationTypeNames); + } + + return sb.append("}").toString(); + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index e4a6c3a7..eba4c3ad 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -16,6 +16,7 @@ import org.jd.core.v1.model.javasyntax.CompilationUnit; import org.jd.core.v1.model.javasyntax.declaration.ExpressionVariableInitializer; import org.jd.core.v1.model.javasyntax.declaration.FieldDeclarator; +import org.jd.core.v1.model.javasyntax.declaration.ModuleDeclaration; import org.jd.core.v1.model.javasyntax.declaration.TypeDeclaration; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; @@ -54,6 +55,8 @@ public void process(Message message) throws Exception { typeDeclaration = convertEnumDeclaration(signatureParser, annotationConverter, classFile, null); } else if ((flags & Constants.ACC_ANNOTATION) != 0) { typeDeclaration = convertAnnotationDeclaration(signatureParser, annotationConverter, classFile, null); + } else if ((flags & Constants.ACC_MODULE) != 0) { + typeDeclaration = convertModuleDeclaration(classFile); } else if ((flags & Constants.ACC_INTERFACE) != 0) { typeDeclaration = convertInterfaceDeclaration(signatureParser, annotationConverter, classFile, null); } else { @@ -271,4 +274,63 @@ protected ExpressionVariableInitializer convertFieldInitializer(Field field, Typ return new ExpressionVariableInitializer(expression); } } + + protected ModuleDeclaration convertModuleDeclaration(ClassFile classFile) { + AttributeModule attributeModule = classFile.getAttribute("Module"); + List requires = convertModuleDeclarationModuleInfo(attributeModule.getRequires()); + List exports = convertModuleDeclarationPackageInfo(attributeModule.getExports()); + List opens = convertModuleDeclarationPackageInfo(attributeModule.getOpens()); + DefaultList uses = new DefaultList<>(attributeModule.getUses()); + List provides = convertModuleDeclarationServiceInfo(attributeModule.getProvides()); + + return new ModuleDeclaration( + attributeModule.getFlags(), attributeModule.getName(), attributeModule.getName(), + attributeModule.getVersion(), requires, exports, opens, uses, provides); + } + + protected List convertModuleDeclarationModuleInfo(ModuleInfo[] moduleInfos) { + if ((moduleInfos == null) || (moduleInfos.length == 0)) { + return null; + } else { + DefaultList list = new DefaultList<>(moduleInfos.length); + + for (ModuleInfo moduleInfo : moduleInfos) { + list.add(new ModuleDeclaration.ModuleInfo(moduleInfo.getName(), moduleInfo.getFlags(), moduleInfo.getVersion())); + } + + return list; + } + } + + protected List convertModuleDeclarationPackageInfo(PackageInfo[] packageInfos) { + if ((packageInfos == null) || (packageInfos.length == 0)) { + return null; + } else { + DefaultList list = new DefaultList<>(packageInfos.length); + + for (PackageInfo packageInfo : packageInfos) { + DefaultList moduleInfoNames = (packageInfo.getModuleInfoNames() == null) ? + null : new DefaultList(packageInfo.getModuleInfoNames()); + list.add(new ModuleDeclaration.PackageInfo(packageInfo.getInternalName(), packageInfo.getFlags(), moduleInfoNames)); + } + + return list; + } + } + + protected List convertModuleDeclarationServiceInfo(ServiceInfo[] serviceInfos) { + if ((serviceInfos == null) || (serviceInfos.length == 0)) { + return null; + } else { + DefaultList list = new DefaultList<>(serviceInfos.length); + + for (ServiceInfo serviceInfo : serviceInfos) { + DefaultList implementationTypeNames = (serviceInfo.getImplementationTypeNames() == null) ? + null : new DefaultList(serviceInfo.getImplementationTypeNames()); + list.add(new ModuleDeclaration.ServiceInfo(serviceInfo.getInterfaceTypeName(), implementationTypeNames)); + } + + return list; + } + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index a3cd0ac4..d973a40d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -94,7 +94,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa // Initialize local variables from 'LocalVariableTable' and 'LocalVariableTypeTable' attributes initLocalVariablesFromAttributes(method); - // Initialize local variables from access flag & signature + // Initialize local variables from access flags & signature int firstVariableIndex = 0; if ((method.getAccessFlags() & FLAG_STATIC) == 0) { @@ -358,7 +358,7 @@ public AbstractLocalVariable getPrimitiveLocalVariableInAssignment(int index, in Type valueType = value.getType(); if (lv.isAssignable(valueType)) { - // Reduce lastType flag + // Reduce lastType flags lv.leftReduce(valueType); } else { // Not assignable -> Create a new local variable diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java index 2041c958..f74d34c4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java @@ -407,13 +407,13 @@ private Object[] loadConstants(ClassFileReader reader) throws UTFDataFormatExcep case 7: constants[i] = new ConstantClass(reader.readUnsignedShort()); break; - case 8: case 16: + case 8: case 16: case 19: case 20: reader.skip(2); break; case 15: reader.skip(3); break; - case 3: case 4: case 9: case 10: case 11: case 12: case 18: + case 3: case 4: case 9: case 10: case 11: case 12: case 17: case 18: reader.skip(4); break; case 5: case 6: diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index e5da834e..38ded31b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -862,7 +862,7 @@ protected boolean checkFieldReference(String fieldName, Expression expression) { @SuppressWarnings("unchecked") protected Expression createObjectTypeReferenceDotClassExpression(int lineNumber, String fieldName, MethodInvocationExpression mie) { - // Add SYNTHETIC flag to field + // Add SYNTHETIC flags to field memberVisitor.init(fieldName); for (ClassFileFieldDeclaration field : bodyDeclaration.getFieldDeclarations()) { @@ -873,7 +873,7 @@ protected Expression createObjectTypeReferenceDotClassExpression(int lineNumber, } } - // Add SYNTHETIC flag to method named 'class$' + // Add SYNTHETIC flags to method named 'class$' memberVisitor.init("class$"); for (ClassFileConstructorOrMethodDeclaration member : bodyDeclaration.getMethodDeclarations()) { diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 97261970..033eae69 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -101,7 +101,7 @@ protected ClassFile loadClassFile(ClassFileReader reader) throws UTFDataFormatEx int superClassIndex = reader.readUnsignedShort(); String internalTypeName = constants.getConstantTypeName(thisClassIndex); - String superTypeName = "java/lang/Object".equals(internalTypeName) ? null : constants.getConstantTypeName(superClassIndex); + String superTypeName = (superClassIndex == 0) ? null : constants.getConstantTypeName(superClassIndex); String[] interfaceTypeNames = loadInterfaces(reader, constants); Field[] fields = loadFields(reader, constants); Method[] methods = loadMethods(reader, constants); @@ -137,13 +137,13 @@ protected Constant[] loadConstants(ClassFileReader reader) throws UTFDataFormatE case 6: constants[i++] = new ConstantDouble(reader.readDouble()); break; - case 7: + case 7: case 19: case 20: constants[i] = new ConstantClass(reader.readUnsignedShort()); break; case 8: constants[i] = new ConstantString(reader.readUnsignedShort()); break; - case 9: case 10: case 11: case 18: + case 9: case 10: case 11: case 17: case 18: constants[i] = new ConstantMemberRef(reader.readUnsignedShort(), reader.readUnsignedShort()); break; case 12: @@ -277,6 +277,26 @@ protected HashMap loadAttributes(ClassFileReader reader, Cons case "LineNumberTable": attributes.put(name, new AttributeLineNumberTable(loadLineNumbers(reader))); break; + case "MethodParameters": + attributes.put(name, new AttributeMethodParameters(loadParameters(reader, constants))); + break; + case "Module": + attributes.put(name, new AttributeModule( + constants.getConstantTypeName(reader.readUnsignedShort()), + reader.readUnsignedShort(), + constants.getConstantString(reader.readUnsignedShort()), + loadModuleInfos(reader, constants), + loadPackageInfos(reader, constants), + loadPackageInfos(reader, constants), + loadConstantClassNames(reader, constants), + loadServiceInfos(reader, constants))); + break; + case "ModulePackages": + attributes.put(name, new AttributeModulePackages(loadConstantClassNames(reader, constants))); + break; + case "ModuleMainClass": + attributes.put(name, new AttributeModuleMainClass(constants.getConstant(reader.readUnsignedShort()))); + break; case "RuntimeInvisibleAnnotations": case "RuntimeVisibleAnnotations": Annotation[] annotations = loadAnnotations(reader, constants); @@ -290,16 +310,12 @@ protected HashMap loadAttributes(ClassFileReader reader, Cons case "Signature": if (attributeLength != 2) throw new ClassFileFormatException("Invalid attribute length"); - int signatureIndex = reader.readUnsignedShort(); - String signature = constants.getConstantString(signatureIndex); - attributes.put(name, new AttributeSignature(signature)); + attributes.put(name, new AttributeSignature(constants.getConstantString(reader.readUnsignedShort()))); break; case "SourceFile": if (attributeLength != 2) throw new ClassFileFormatException("Invalid attribute length"); - int sourceFileIndex = reader.readUnsignedShort(); - String sourceFile = constants.getConstantString(sourceFileIndex); - attributes.put(name, new AttributeSourceFile(sourceFile)); + attributes.put(name, new AttributeSourceFile(constants.getConstantString(reader.readUnsignedShort()))); break; case "Synthetic": if (attributeLength != 0) @@ -539,6 +555,94 @@ protected LineNumber[] loadLineNumbers(ClassFileReader reader) { return lineNumbers; } + protected MethodParameter[] loadParameters(ClassFileReader reader, ConstantPool constants) { + int count = reader.readUnsignedShort(); + if (count == 0) + return null; + + MethodParameter[] parameters = new MethodParameter[count]; + + for (int i=0; i iterator = declaration.getRequires().iterator(); + visitModuleDeclaration(iterator.next()); + while (iterator.hasNext()) { + tokens.add(NewLineToken.NEWLINE_1); + visitModuleDeclaration(iterator.next()); + } + needNewLine = true; + } + + if ((declaration.getExports() != null) && !declaration.getExports().isEmpty()) { + if (needNewLine) { + tokens.add(NewLineToken.NEWLINE_2); + } + Iterator iterator = declaration.getExports().iterator(); + visitModuleDeclaration(iterator.next(), EXPORTS); + while (iterator.hasNext()) { + tokens.add(NewLineToken.NEWLINE_1); + visitModuleDeclaration(iterator.next(), EXPORTS); + } + needNewLine = true; + } + + if ((declaration.getOpens() != null) && !declaration.getOpens().isEmpty()) { + if (needNewLine) { + tokens.add(NewLineToken.NEWLINE_2); + } + Iterator iterator = declaration.getOpens().iterator(); + visitModuleDeclaration(iterator.next(), OPENS); + while (iterator.hasNext()) { + tokens.add(NewLineToken.NEWLINE_1); + visitModuleDeclaration(iterator.next(), OPENS); + } + needNewLine = true; + } + + if ((declaration.getUses() != null) && !declaration.getUses().isEmpty()) { + if (needNewLine) { + tokens.add(NewLineToken.NEWLINE_2); + } + Iterator iterator = declaration.getUses().iterator(); + visitModuleDeclaration(iterator.next()); + while (iterator.hasNext()) { + tokens.add(NewLineToken.NEWLINE_1); + visitModuleDeclaration(iterator.next()); + } + needNewLine = true; + } + + if ((declaration.getProvides() != null) && !declaration.getProvides().isEmpty()) { + if (needNewLine) { + tokens.add(NewLineToken.NEWLINE_2); + } + Iterator iterator = declaration.getProvides().iterator(); + visitModuleDeclaration(iterator.next()); + while (iterator.hasNext()) { + tokens.add(NewLineToken.NEWLINE_1); + visitModuleDeclaration(iterator.next()); + } + } + + fragments.addTokensFragment(tokens); + + JavaFragmentFactory.addEndTypeBody(fragments, start); + + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + } + + protected void visitModuleDeclaration(ModuleDeclaration.ModuleInfo moduleInfo) { + tokens.add(REQUIRES); + + if ((moduleInfo.getFlags() & FLAG_TRANSITIVE) != 0) { + tokens.add(TextToken.SPACE); + tokens.add(TRANSITIVE); + } + + tokens.add(TextToken.SPACE); + tokens.add(new TextToken(moduleInfo.getName())); + tokens.add(TextToken.SEMICOLON); + } + + protected void visitModuleDeclaration(ModuleDeclaration.PackageInfo packageInfo, KeywordToken keywordToken) { + tokens.add(keywordToken); + tokens.add(TextToken.SPACE); + tokens.add(new TextToken(packageInfo.getInternalName().replace('/', '.'))); + + if ((packageInfo.getModuleInfoNames() != null) && !packageInfo.getModuleInfoNames().isEmpty()) { + tokens.add(TextToken.SPACE); + tokens.add(TO); + + if (packageInfo.getModuleInfoNames().size() == 1) { + tokens.add(TextToken.SPACE); + tokens.add(new TextToken(packageInfo.getModuleInfoNames().get(0))); + } else { + tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + + Iterator iterator = packageInfo.getModuleInfoNames().iterator(); + + tokens.add(new TextToken(iterator.next())); + + while (iterator.hasNext()) { + tokens.add(TextToken.COMMA); + tokens.add(NewLineToken.NEWLINE_1); + tokens.add(new TextToken(iterator.next())); + } + + tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + } + } + + tokens.add(TextToken.SEMICOLON); + } + + protected void visitModuleDeclaration(String internalTypeName) { + tokens.add(USES); + tokens.add(TextToken.SPACE); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + tokens.add(TextToken.SEMICOLON); + } + + protected void visitModuleDeclaration(ModuleDeclaration.ServiceInfo serviceInfo) { + tokens.add(PROVIDES); + tokens.add(TextToken.SPACE); + String internalTypeName = serviceInfo.getInterfaceTypeName(); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + tokens.add(TextToken.SPACE); + tokens.add(WITH); + + if (serviceInfo.getImplementationTypeNames().size() == 1) { + tokens.add(TextToken.SPACE); + internalTypeName = serviceInfo.getImplementationTypeNames().get(0); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + } else { + tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); + tokens.add(NewLineToken.NEWLINE_1); + + Iterator iterator = serviceInfo.getImplementationTypeNames().iterator(); + + internalTypeName = iterator.next(); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + + while (iterator.hasNext()) { + tokens.add(TextToken.COMMA); + tokens.add(NewLineToken.NEWLINE_1); + internalTypeName = iterator.next(); + tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + } + + tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); + } + + tokens.add(TextToken.SEMICOLON); + } + @Override public void visit(LocalVariableDeclaration declaration) { if (declaration.isFinal()) { diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index 80c9f6c0..423bbaf3 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -28,13 +28,23 @@ public class TypeVisitor extends AbstractJavaSyntaxVisitor { public static final KeywordToken BYTE = new KeywordToken("byte"); public static final KeywordToken CHAR = new KeywordToken("char"); public static final KeywordToken DOUBLE = new KeywordToken("double"); + public static final KeywordToken EXPORTS = new KeywordToken("exports"); public static final KeywordToken EXTENDS = new KeywordToken("extends"); public static final KeywordToken FLOAT = new KeywordToken("float"); public static final KeywordToken INT = new KeywordToken("int"); public static final KeywordToken LONG = new KeywordToken("long"); + public static final KeywordToken MODULE = new KeywordToken("module"); + public static final KeywordToken OPEN = new KeywordToken("open"); + public static final KeywordToken OPENS = new KeywordToken("opens"); + public static final KeywordToken PROVIDES = new KeywordToken("provides"); + public static final KeywordToken REQUIRES = new KeywordToken("requires"); public static final KeywordToken SHORT = new KeywordToken("short"); public static final KeywordToken SUPER = new KeywordToken("super"); + public static final KeywordToken TO = new KeywordToken("to"); + public static final KeywordToken TRANSITIVE = new KeywordToken("transitive"); + public static final KeywordToken USES = new KeywordToken("uses"); public static final KeywordToken VOID = new KeywordToken("void"); + public static final KeywordToken WITH = new KeywordToken("with"); public static final int UNKNOWN_LINE_NUMBER = Printer.UNKNOWN_LINE_NUMBER; diff --git a/src/main/java/org/jd/core/v1/util/DefaultList.java b/src/main/java/org/jd/core/v1/util/DefaultList.java index 253e5346..95f47114 100644 --- a/src/main/java/org/jd/core/v1/util/DefaultList.java +++ b/src/main/java/org/jd/core/v1/util/DefaultList.java @@ -35,7 +35,7 @@ public DefaultList(Collection collection) { } public DefaultList(E element, E... elements) { - super(elements.length + 1); + ensureCapacity(elements.length + 1); add(element); @@ -44,6 +44,16 @@ public DefaultList(E element, E... elements) { } } + public DefaultList(E[] elements) { + if ((elements != null) && (elements.length > 0)) { + ensureCapacity(elements.length); + + for (E e : elements) { + add(e); + } + } + } + public E getFirst() { return (E)get(0); } From 045c7ddb71e738e4a874d6f9722b1d7ee7b99823 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 1 Jun 2019 22:27:32 +0200 Subject: [PATCH 022/211] Fixed #244, bug on "MethodParameters" attribute parsing --- .../service/deserializer/classfile/ClassFileDeserializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 033eae69..5b21ed14 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -556,7 +556,7 @@ protected LineNumber[] loadLineNumbers(ClassFileReader reader) { } protected MethodParameter[] loadParameters(ClassFileReader reader, ConstantPool constants) { - int count = reader.readUnsignedShort(); + int count = reader.readUnsignedByte(); if (count == 0) return null; From b55c932f3cccaef17a459b8180b358a520faaafd Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 3 Jun 2019 23:02:11 +0200 Subject: [PATCH 023/211] Update API for Java modules --- README.md | 6 +- .../org/jd/core/v1/api/printer/Printer.java | 24 +++-- .../core/v1/model/token/DeclarationToken.java | 24 +++-- .../core/v1/model/token/EndMarkerToken.java | 8 +- .../core/v1/model/token/ReferenceToken.java | 6 +- .../core/v1/model/token/StartMarkerToken.java | 8 +- .../visitor/ExpressionVisitor.java | 10 +- .../visitor/TypeVisitor.java | 10 +- .../visitor/TokenizeJavaFragmentVisitor.java | 2 +- .../writer/visitor/PrintTokenVisitor.java | 4 +- .../jd/core/v1/JavaFragmentToTokenTest.java | 102 +++++++++--------- .../java/org/jd/core/v1/WriteTokenTest.java | 46 ++++---- .../core/v1/printer/PlainTextMetaPrinter.java | 56 +++++----- .../jd/core/v1/printer/PlainTextPrinter.java | 4 +- 14 files changed, 161 insertions(+), 149 deletions(-) diff --git a/README.md b/README.md index be60eab2..d8423df4 100644 --- a/README.md +++ b/README.md @@ -86,11 +86,11 @@ Printer printer = new Printer() { @Override public void printNumericConstant(String constant) { sb.append(constant); } @Override public void printStringConstant(String constant, String ownerInternalName) { sb.append(constant); } @Override public void printKeyword(String keyword) { sb.append(keyword); } - @Override public void printDeclaration(int flags, String internalTypeName, String name, String descriptor) { sb.append(name); } - @Override public void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName) { sb.append(name); } + @Override public void printDeclaration(int type, String internalTypeName, String name, String descriptor) { sb.append(name); } + @Override public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) { sb.append(name); } @Override public void indent() { this.indentationCount++; } - @Override public void unindent() { if (this.indentationCount > 0) this.indentationCount--; } + @Override public void unindent() { this.indentationCount--; } @Override public void startLine(int lineNumber) { for (int i=0; ipublic class TokenWriterTest<-- 0,1,2:2 + * [ 3: 0 ] -->public class TokenWriterTest<-- 0,1,2:2 * [ 4: 0 ] { - * [ 5: 0 ] -->public static void main(String[] args)<-- 0,0,2:11 { + * [ 5: 0 ] -->public static void main(String[] args)<-- 0,0,2:11 { * [ 6: lineNumber1] -->int i = 0;<-- 0,1,2147483647:4 * [ 7: 0 ] * [ 8: 0 ] -->try<-- 0,1,2:5 { * [ 9: lineNumber2] --><-- 0,0,2147483647:19 -->i = 1;<-- 0,0,2147483647:18 --><-- 0,1,2:5 - * [ 10: 0 ] } -->catch (RuntimeException e)<-- 0,1,2:5 { + * [ 10: 0 ] } -->catch (RuntimeException e)<-- 0,1,2:5 { * [ 11: lineNumber3] --><-- 0,0,2147483647:19 -->i = 2;<-- 0,0,2147483647:18 --><-- 0,1,2:5 * [ 12: 0 ] } -->finally<-- 0,1,2:5 { * [ 13: lineNumber4] --><-- 0,0,2147483647:19 -->i = 3;<-- 0,0,2147483647:18 --><-- 0,1,2:5 @@ -1720,7 +1720,7 @@ public Message createMessageToTestLinkedBlocks(int lineNumber1, int lineNumber2, TextToken.SPACE, CLASS, TextToken.SPACE, - new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null) + new DeclarationToken(DeclarationToken.TYPE, "org/jd/core/v1/service/test/TokenWriterTest", "TokenWriterTest", null) )); StartBodyFragment startMainClass = JavaFragmentFactory.addStartTypeBody(fragments); @@ -1734,9 +1734,9 @@ public Message createMessageToTestLinkedBlocks(int lineNumber1, int lineNumber2, TextToken.SPACE, VOID, TextToken.SPACE, - new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), + new DeclarationToken(DeclarationToken.METHOD, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), TextToken.LEFTROUNDBRACKET, - new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), + new ReferenceToken(ReferenceToken.TYPE, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), new TextToken("[] args)") )); @@ -1766,7 +1766,7 @@ public Message createMessageToTestLinkedBlocks(int lineNumber1, int lineNumber2, fragments.add(new TokensFragment( CATCH, new TextToken(" ("), - new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/RuntimeException", "RuntimeException", null, "org/jd/core/v1/service/test/TokenWriterTest"), + new ReferenceToken(ReferenceToken.TYPE, "java/lang/RuntimeException", "RuntimeException", null, "org/jd/core/v1/service/test/TokenWriterTest"), new TextToken(" e)") )); diff --git a/src/test/java/org/jd/core/v1/WriteTokenTest.java b/src/test/java/org/jd/core/v1/WriteTokenTest.java index 79a3cc5a..6b998dfa 100644 --- a/src/test/java/org/jd/core/v1/WriteTokenTest.java +++ b/src/test/java/org/jd/core/v1/WriteTokenTest.java @@ -43,7 +43,7 @@ public void writeClassDeclaration() throws Exception { // import javasyntax.util.ArrayList;\n tokens.add(IMPORT); tokens.add(TextToken.SPACE); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/util/ArrayList", "java.util.ArrayList", null, null)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, "java/util/ArrayList", "java.util.ArrayList", null, null)); tokens.add(TextToken.SEMICOLON); tokens.add(NewLineToken.NEWLINE_1); @@ -52,7 +52,7 @@ public void writeClassDeclaration() throws Exception { tokens.add(TextToken.SPACE); tokens.add(STATIC); tokens.add(TextToken.SPACE); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "org/junit/Assert/*", "org.junit.Assert.*", null, null)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, "org/junit/Assert/*", "org.junit.Assert.*", null, null)); tokens.add(TextToken.SEMICOLON); tokens.add(NewLineToken.NEWLINE_2); @@ -61,7 +61,7 @@ public void writeClassDeclaration() throws Exception { tokens.add(TextToken.SPACE); tokens.add(CLASS); tokens.add(TextToken.SPACE); - tokens.add(new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "WriteTokenTest", null)); + tokens.add(new DeclarationToken(DeclarationToken.TYPE, "org/jd/core/v1/service/test/WriteTokenTest", "WriteTokenTest", null)); tokens.add(TextToken.SPACE); tokens.add(StartBlockToken.START_BLOCK); tokens.add(NewLineToken.NEWLINE_1); @@ -73,9 +73,9 @@ public void writeClassDeclaration() throws Exception { tokens.add(TextToken.SPACE); tokens.add(VOID); tokens.add(TextToken.SPACE); - tokens.add(new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "main", "([Ljava/lang/String;)V")); + tokens.add(new DeclarationToken(DeclarationToken.METHOD, "org/jd/core/v1/service/test/WriteTokenTest", "main", "([Ljava/lang/String;)V")); tokens.add(TextToken.LEFTROUNDBRACKET); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/String", "String", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, "java/lang/String", "String", null, "org/jd/core/v1/service/test/WriteTokenTest")); tokens.add(new TextToken("[] args) ")); tokens.add(StartBlockToken.START_BLOCK); tokens.add(NewLineToken.NEWLINE_1); @@ -109,7 +109,7 @@ public void writeClassDeclaration() throws Exception { tokens.add(new LineNumberToken(10)); tokens.add(INT); tokens.add(new TextToken(" i = ")); - tokens.add(new ReferenceToken(ReferenceToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "call", "(IILjava/util/Enumeration;I)V", "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new ReferenceToken(ReferenceToken.METHOD, "org/jd/core/v1/service/test/WriteTokenTest", "call", "(IILjava/util/Enumeration;I)V", "org/jd/core/v1/service/test/WriteTokenTest")); tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); tokens.add(NewLineToken.NEWLINE_1); tokens.add(new LineNumberToken(11)); @@ -122,7 +122,7 @@ public void writeClassDeclaration() throws Exception { tokens.add(new LineNumberToken(13)); tokens.add(NEW); tokens.add(TextToken.SPACE); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/util/Enumeration", "Enumeration", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, "java/util/Enumeration", "Enumeration", null, "org/jd/core/v1/service/test/WriteTokenTest")); tokens.add(new TextToken("() ")); tokens.add(StartBlockToken.START_BLOCK); tokens.add(NewLineToken.NEWLINE_1); @@ -131,7 +131,7 @@ public void writeClassDeclaration() throws Exception { tokens.add(TextToken.SPACE); tokens.add(BOOLEAN); tokens.add(TextToken.SPACE); - tokens.add(new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest$1", "hasMoreElements", "()Z")); + tokens.add(new DeclarationToken(DeclarationToken.METHOD, "org/jd/core/v1/service/test/WriteTokenTest$1", "hasMoreElements", "()Z")); tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); tokens.add(TextToken.SPACE); @@ -149,9 +149,9 @@ public void writeClassDeclaration() throws Exception { // public Object nextElement()... tokens.add(PUBLIC); tokens.add(TextToken.SPACE); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/Object", "Object", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, "java/lang/Object", "Object", null, "org/jd/core/v1/service/test/WriteTokenTest")); tokens.add(TextToken.SPACE); - tokens.add(new DeclarationToken(DeclarationToken.METHOD_FLAG, "org/jd/core/v1/service/test/WriteTokenTest$1", "nextElement", "()Ljava/lang/Object;")); + tokens.add(new DeclarationToken(DeclarationToken.METHOD, "org/jd/core/v1/service/test/WriteTokenTest$1", "nextElement", "()Ljava/lang/Object;")); tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); tokens.add(TextToken.SPACE); @@ -178,11 +178,11 @@ public void writeClassDeclaration() throws Exception { // System.out.println(i); tokens.add(new LineNumberToken(22)); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, "java/lang/System", "System", null, "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, "java/lang/System", "System", null, "org/jd/core/v1/service/test/WriteTokenTest")); tokens.add(TextToken.DOT); - tokens.add(new ReferenceToken(ReferenceToken.FIELD_FLAG, "java/lang/System", "out", "java/io/PrintStream", "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new ReferenceToken(ReferenceToken.FIELD, "java/lang/System", "out", "java/io/PrintStream", "org/jd/core/v1/service/test/WriteTokenTest")); tokens.add(TextToken.DOT); - tokens.add(new ReferenceToken(ReferenceToken.METHOD_FLAG, "java/io/PrintStream", "println", "(I)V", "org/jd/core/v1/service/test/WriteTokenTest")); + tokens.add(new ReferenceToken(ReferenceToken.METHOD, "java/io/PrintStream", "println", "(I)V", "org/jd/core/v1/service/test/WriteTokenTest")); tokens.add(TextToken.LEFTROUNDBRACKET); tokens.add(new TextToken("i")); tokens.add(TextToken.RIGHTROUNDBRACKET); @@ -216,26 +216,26 @@ public void writeClassDeclaration() throws Exception { String expected = "[ 1: 0] package org.jd.core.v1.service.test;\n" + "[ 2: 0] \n" + - "[ 3: 0] import java.util.ArrayList;\n" + - "[ 4: 0] import static org.junit.Assert.*;\n" + + "[ 3: 0] import java.util.ArrayList;\n" + + "[ 4: 0] import static org.junit.Assert.*;\n" + "[ 5: 0] \n" + - "[ 6: 0] public class WriteTokenTest {\n" + - "[ 7: 0] public static void main(String[] args) {\n" + + "[ 6: 0] public class WriteTokenTest {\n" + + "[ 7: 0] public static void main(String[] args) {\n" + "[ 8: 8] if (args == null)\n" + "[ 9: 0] return;\n" + - "[ 10: 10] int i = call(\n" + + "[ 10: 10] int i = call(\n" + "[ 11: 11] \"aaaa\",\n" + "[ 12: 12] b,\n" + - "[ 13: 13] new Enumeration() {\n" + - "[ 14: 0] public boolean hasMoreElements() {\n" + + "[ 13: 13] new Enumeration() {\n" + + "[ 14: 0] public boolean hasMoreElements() {\n" + "[ 15: 15] return false;\n" + "[ 16: 0] }\n" + - "[ 17: 0] public Object nextElement() {\n" + + "[ 17: 0] public Object nextElement() {\n" + "[ 18: 18] return null;\n" + "[ 19: 0] }\n" + "[ 20: 0] },\n" + "[ 21: 21] c);\n" + - "[ 22: 22] System.out.println(i);\n" + + "[ 22: 22] System.out.println(i);\n" + "[ 23: 0] }\n" + "[ 24: 0] }\n"; @@ -269,7 +269,7 @@ public void testComments() throws Exception { tokens.add(TextToken.SPACE); tokens.add(CLASS); tokens.add(TextToken.SPACE); - tokens.add(new DeclarationToken(DeclarationToken.TYPE_FLAG, "org/jd/core/v1/service/test/WriteTokenTest", "WriteTokenTest", null)); + tokens.add(new DeclarationToken(DeclarationToken.TYPE, "org/jd/core/v1/service/test/WriteTokenTest", "WriteTokenTest", null)); tokens.add(TextToken.SPACE); tokens.add(StartBlockToken.START_BLOCK); tokens.add(NewLineToken.NEWLINE_1); diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java index e5b15eb6..fa9d6ae1 100644 --- a/src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java +++ b/src/test/java/org/jd/core/v1/printer/PlainTextMetaPrinter.java @@ -16,10 +16,10 @@ public void printStringConstant(String constant, String ownerInternalName) { sb.append("'/>"); } - public void printDeclaration(int flags, String internalTypeName, String name, String descriptor) { + public void printDeclaration(int type, String internalTypeName, String name, String descriptor) { sb.append(name); - sb.append(""); } - public void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName) { + public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) { sb.append(name); - sb.append(""); } - protected void printFlags(int flags) { - if ((flags & TYPE_FLAG) != 0) { - sb.append("+TYPE"); - } - if ((flags & FIELD_FLAG) != 0) { - sb.append("+FIELD"); - } - if ((flags & METHOD_FLAG) != 0) { - sb.append("+METHOD"); - } - if ((flags & CONSTRUCTOR_FLAG) != 0) { - sb.append("+CONSTRUCTOR"); + protected void printType(int type) { + switch (type) { + case TYPE: + sb.append("TYPE"); + break; + case FIELD: + sb.append("FIELD"); + break; + case METHOD: + sb.append("METHOD"); + break; + case CONSTRUCTOR: + sb.append("CONSTRUCTOR"); + break; + case PACKAGE: + sb.append("PACKAGE"); + break; + case MODULE: + sb.append("MODULE"); + break; } } - protected void printMarker(int marker) { - switch (marker) { - case COMMENT_TYPE: + protected void printMarker(int type) { + switch (type) { + case COMMENT: sb.append("COMMENT"); break; - case JAVADOC_TYPE: + case JAVADOC: sb.append("JAVADOC"); break; - case ERROR_TYPE: + case ERROR: sb.append("ERROR"); break; - case IMPORT_STATEMENTS_TYPE: + case IMPORT_STATEMENTS: sb.append("IMPORT_STATEMENTS"); break; } diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java index ee616a94..8b6b48da 100644 --- a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java +++ b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java @@ -82,9 +82,9 @@ public void printText(String text) { public void printKeyword(String keyword) { sb.append(keyword); } - public void printDeclaration(int flags, String internalTypeName, String name, String descriptor) { printText(name); } + public void printDeclaration(int type, String internalTypeName, String name, String descriptor) { printText(name); } - public void printReference(int flags, String internalTypeName, String name, String descriptor, String ownerInternalName) { printText(name); } + public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) { printText(name); } public void indent() { this.indentationCount++; From 411784babd767c6181c5f467e54e29b2944ee784 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 3 Jun 2019 23:02:48 +0200 Subject: [PATCH 024/211] Update API for Java modules --- .../visitor/CompilationUnitVisitor.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 719bcf4d..78227331 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -349,7 +349,7 @@ public void visit(ConstructorDeclaration declaration) { } // Build token for type declaration - tokens.add(new DeclarationToken(DeclarationToken.CONSTRUCTOR_FLAG, currentInternalTypeName, currentTypeName, declaration.getDescriptor())); + tokens.add(new DeclarationToken(DeclarationToken.CONSTRUCTOR, currentInternalTypeName, currentTypeName, declaration.getDescriptor())); storeContext(); currentMethodParamNames.clear(); @@ -569,7 +569,7 @@ public void visit(EnumDeclaration.Constant declaration) { // Build token for type declaration tokens.addLineNumberToken(declaration.getLineNumber()); - tokens.add(new DeclarationToken(DeclarationToken.FIELD_FLAG, currentInternalTypeName, declaration.getName(), 'L' + currentInternalTypeName + ';')); + tokens.add(new DeclarationToken(DeclarationToken.FIELD, currentInternalTypeName, declaration.getName(), 'L' + currentInternalTypeName + ';')); storeContext(); currentMethodParamNames.clear(); @@ -648,19 +648,19 @@ public void visit(FieldDeclarator fieldDeclarator) { switch (fieldDeclarator.getDimension()) { case 0: - tokens.add(new DeclarationToken(DeclarationToken.FIELD_FLAG, currentInternalTypeName, fieldDeclarator.getName(), descriptor)); + tokens.add(new DeclarationToken(DeclarationToken.FIELD, currentInternalTypeName, fieldDeclarator.getName(), descriptor)); break; case 1: - tokens.add(new DeclarationToken(DeclarationToken.FIELD_FLAG, currentInternalTypeName, fieldDeclarator.getName(), "[" + descriptor)); + tokens.add(new DeclarationToken(DeclarationToken.FIELD, currentInternalTypeName, fieldDeclarator.getName(), "[" + descriptor)); tokens.add(TextToken.DIMENSION_1); break; case 2: - tokens.add(new DeclarationToken(DeclarationToken.FIELD_FLAG, currentInternalTypeName, fieldDeclarator.getName(), "[[" + descriptor)); + tokens.add(new DeclarationToken(DeclarationToken.FIELD, currentInternalTypeName, fieldDeclarator.getName(), "[[" + descriptor)); tokens.add(TextToken.DIMENSION_2); break; default: descriptor = new String(new char[fieldDeclarator.getDimension()]).replaceAll("\0", "[") + descriptor; - tokens.add(new DeclarationToken(DeclarationToken.FIELD_FLAG, currentInternalTypeName, fieldDeclarator.getName(), descriptor)); + tokens.add(new DeclarationToken(DeclarationToken.FIELD, currentInternalTypeName, fieldDeclarator.getName(), descriptor)); tokens.add(newTextToken(new String(new char[fieldDeclarator.getDimension()]).replaceAll("\0", "[]"))); break; } @@ -827,7 +827,7 @@ public void visit(ModuleDeclaration declaration) { tokens.add(MODULE); tokens.add(TextToken.SPACE); - tokens.add(new TextToken(declaration.getName())); + tokens.add(new DeclarationToken(DeclarationToken.MODULE, declaration.getName().replace('.', '/'), declaration.getName(), null)); fragments.addTokensFragment(tokens); StartBodyFragment start = JavaFragmentFactory.addStartTypeBody(fragments); @@ -905,20 +905,24 @@ public void visit(ModuleDeclaration declaration) { protected void visitModuleDeclaration(ModuleDeclaration.ModuleInfo moduleInfo) { tokens.add(REQUIRES); + if ((moduleInfo.getFlags() & FLAG_STATIC) != 0) { + tokens.add(TextToken.SPACE); + tokens.add(STATIC); + } if ((moduleInfo.getFlags() & FLAG_TRANSITIVE) != 0) { tokens.add(TextToken.SPACE); tokens.add(TRANSITIVE); } tokens.add(TextToken.SPACE); - tokens.add(new TextToken(moduleInfo.getName())); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfo.getName().replace('.', '/'), moduleInfo.getName(), null, null)); tokens.add(TextToken.SEMICOLON); } protected void visitModuleDeclaration(ModuleDeclaration.PackageInfo packageInfo, KeywordToken keywordToken) { tokens.add(keywordToken); tokens.add(TextToken.SPACE); - tokens.add(new TextToken(packageInfo.getInternalName().replace('/', '.'))); + tokens.add(new ReferenceToken(ReferenceToken.PACKAGE, packageInfo.getInternalName(), packageInfo.getInternalName().replace('/', '.'), null, null)); if ((packageInfo.getModuleInfoNames() != null) && !packageInfo.getModuleInfoNames().isEmpty()) { tokens.add(TextToken.SPACE); @@ -926,19 +930,22 @@ protected void visitModuleDeclaration(ModuleDeclaration.PackageInfo packageInfo, if (packageInfo.getModuleInfoNames().size() == 1) { tokens.add(TextToken.SPACE); - tokens.add(new TextToken(packageInfo.getModuleInfoNames().get(0))); + String moduleInfoName = packageInfo.getModuleInfoNames().get(0); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfoName.replace('.', '/'), moduleInfoName, null, null)); } else { tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); tokens.add(NewLineToken.NEWLINE_1); Iterator iterator = packageInfo.getModuleInfoNames().iterator(); - tokens.add(new TextToken(iterator.next())); + String moduleInfoName = iterator.next(); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfoName.replace('.', '/'), moduleInfoName, null, null)); while (iterator.hasNext()) { tokens.add(TextToken.COMMA); tokens.add(NewLineToken.NEWLINE_1); - tokens.add(new TextToken(iterator.next())); + moduleInfoName = iterator.next(); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfoName.replace('.', '/'), moduleInfoName, null, null)); } tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); @@ -951,7 +958,7 @@ protected void visitModuleDeclaration(ModuleDeclaration.PackageInfo packageInfo, protected void visitModuleDeclaration(String internalTypeName) { tokens.add(USES); tokens.add(TextToken.SPACE); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, internalTypeName, internalTypeName.replace('/', '.'), null, null)); tokens.add(TextToken.SEMICOLON); } @@ -959,14 +966,14 @@ protected void visitModuleDeclaration(ModuleDeclaration.ServiceInfo serviceInfo) tokens.add(PROVIDES); tokens.add(TextToken.SPACE); String internalTypeName = serviceInfo.getInterfaceTypeName(); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, internalTypeName, internalTypeName.replace('/', '.'), null, null)); tokens.add(TextToken.SPACE); tokens.add(WITH); if (serviceInfo.getImplementationTypeNames().size() == 1) { tokens.add(TextToken.SPACE); internalTypeName = serviceInfo.getImplementationTypeNames().get(0); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, internalTypeName, internalTypeName.replace('/', '.'), null, null)); } else { tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); tokens.add(NewLineToken.NEWLINE_1); @@ -974,13 +981,13 @@ protected void visitModuleDeclaration(ModuleDeclaration.ServiceInfo serviceInfo) Iterator iterator = serviceInfo.getImplementationTypeNames().iterator(); internalTypeName = iterator.next(); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, internalTypeName, internalTypeName.replace('/', '.'), null, null)); while (iterator.hasNext()) { tokens.add(TextToken.COMMA); tokens.add(NewLineToken.NEWLINE_1); internalTypeName = iterator.next(); - tokens.add(new ReferenceToken(ReferenceToken.TYPE_FLAG, internalTypeName, internalTypeName.replace('/', '.'), null, null)); + tokens.add(new ReferenceToken(ReferenceToken.TYPE, internalTypeName, internalTypeName.replace('/', '.'), null, null)); } tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); @@ -1094,7 +1101,7 @@ public void visit(MethodDeclaration declaration) { tokens.add(TextToken.SPACE); // Build token for type declaration - tokens.add(new DeclarationToken(DeclarationToken.METHOD_FLAG, currentInternalTypeName, declaration.getName(), declaration.getDescriptor())); + tokens.add(new DeclarationToken(DeclarationToken.METHOD, currentInternalTypeName, declaration.getName(), declaration.getDescriptor())); storeContext(); currentMethodParamNames.clear(); @@ -1246,7 +1253,7 @@ protected void buildFragmentsForTypeDeclaration(TypeDeclaration declaration, int tokens.add(TextToken.SPACE); // Build token for type declaration - tokens.add(new DeclarationToken(DeclarationToken.TYPE_FLAG, declaration.getInternalName(), declaration.getName(), null)); + tokens.add(new DeclarationToken(DeclarationToken.TYPE, declaration.getInternalName(), declaration.getName(), null)); } protected void buildFragmentsForClassOrInterfaceDeclaration(InterfaceDeclaration declaration, int flags, KeywordToken keyword) { From 448b1764741b0674958617e87dbab79e3b79afbe Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 3 Jun 2019 23:05:13 +0200 Subject: [PATCH 025/211] Update version to 1.0.4 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b2f5c0be..87916b9d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.0.3' +version='1.0.4' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From cdb695a72ac3d6508c57deb539f3d0cb223fd7c5 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 16 Jun 2019 12:09:03 +0200 Subject: [PATCH 026/211] Add default, private and static methods in interface support --- .../javasyntax/declaration/Declaration.java | 51 +-- .../processor/ConvertClassFileProcessor.java | 16 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 379 ++++++++++++++++++ .../test/InterfaceWithDefaultMethods.java | 21 +- .../resources/zip/data-java-jdk-10.0.2.zip | Bin 14644 -> 14743 bytes .../resources/zip/data-java-jdk-9.0.1.zip | Bin 14630 -> 14729 bytes 6 files changed, 430 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java index 0e12e10d..d5e01f5c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java @@ -9,29 +9,32 @@ public interface Declaration { // Access flags for Class, Field, Method, Nested class, Module, Module Requires, Module Exports, Module Opens - int FLAG_PUBLIC = 0x0001; // C F M N . . . . - int FLAG_PRIVATE = 0x0002; // . F M N . . . . - int FLAG_PROTECTED = 0x0004; // . F M N . . . . - int FLAG_STATIC = 0x0008; // C F M N . . . . - int FLAG_FINAL = 0x0010; // C F M N . . . . - int FLAG_SYNCHRONIZED = 0x0020; // . . M . . . . . - int FLAG_SUPER = 0x0020; // C . . . . . . . - int FLAG_OPEN = 0x0020; // . . . . Mo . . . - int FLAG_TRANSITIVE = 0x0020; // . . . . . MR . . - int FLAG_VOLATILE = 0x0040; // . F . . . . . . - int FLAG_BRIDGE = 0x0040; // . . M . . . . . - int FLAG_STATIC_PHASE = 0x0040; // . . M . . MR . . - int FLAG_TRANSIENT = 0x0080; // . F . . . . . . - int FLAG_VARARGS = 0x0080; // . . M . . . . . - int FLAG_NATIVE = 0x0100; // . . M . . . . . - int FLAG_INTERFACE = 0x0200; // C . . N . . . . - int FLAG_ABSTRACT = 0x0400; // C . M N . . . . - int FLAG_STRICT = 0x0800; // . . M . . . . . - int FLAG_SYNTHETIC = 0x1000; // C F M N Mo MR ME MO - int FLAG_ANNOTATION = 0x2000; // C . . N . . . . - int FLAG_ENUM = 0x4000; // C F . N . . . . - int FLAG_MODULE = 0x8000; // C . . . . . . . - int FLAG_MANDATED = 0x8000; // . . . . Mo MR ME MO - + int FLAG_PUBLIC = 0x0001; // C F M N . . . . + int FLAG_PRIVATE = 0x0002; // . F M N . . . . + int FLAG_PROTECTED = 0x0004; // . F M N . . . . + int FLAG_STATIC = 0x0008; // C F M N . . . . + int FLAG_FINAL = 0x0010; // C F M N . . . . + int FLAG_SYNCHRONIZED = 0x0020; // . . M . . . . . + int FLAG_SUPER = 0x0020; // C . . . . . . . + int FLAG_OPEN = 0x0020; // . . . . Mo . . . + int FLAG_TRANSITIVE = 0x0020; // . . . . . MR . . + int FLAG_VOLATILE = 0x0040; // . F . . . . . . + int FLAG_BRIDGE = 0x0040; // . . M . . . . . + int FLAG_STATIC_PHASE = 0x0040; // . . M . . MR . . + int FLAG_TRANSIENT = 0x0080; // . F . . . . . . + int FLAG_VARARGS = 0x0080; // . . M . . . . . + int FLAG_NATIVE = 0x0100; // . . M . . . . . + int FLAG_INTERFACE = 0x0200; // C . . N . . . . + int FLAG_ABSTRACT = 0x0400; // C . M N . . . . + int FLAG_STRICT = 0x0800; // . . M . . . . . + int FLAG_SYNTHETIC = 0x1000; // C F M N Mo MR ME MO + int FLAG_ANNOTATION = 0x2000; // C . . N . . . . + int FLAG_ENUM = 0x4000; // C F . N . . . . + int FLAG_MODULE = 0x8000; // C . . . . . . . + int FLAG_MANDATED = 0x8000; // . . . . Mo MR ME MO + + // Extension + int FLAG_DEFAULT = 0x10000; // . . M . . . . . + void accept(DeclarationVisitor visitor); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index eba4c3ad..2da27ce9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -14,10 +14,7 @@ import org.jd.core.v1.model.classfile.attribute.*; import org.jd.core.v1.model.classfile.constant.*; import org.jd.core.v1.model.javasyntax.CompilationUnit; -import org.jd.core.v1.model.javasyntax.declaration.ExpressionVariableInitializer; -import org.jd.core.v1.model.javasyntax.declaration.FieldDeclarator; -import org.jd.core.v1.model.javasyntax.declaration.ModuleDeclaration; -import org.jd.core.v1.model.javasyntax.declaration.TypeDeclaration; +import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; import org.jd.core.v1.model.javasyntax.reference.ElementValue; @@ -180,11 +177,18 @@ protected List convertMethods(Signature } else if ("".equals(name)) { list.add(new ClassFileStaticInitializerDeclaration(bodyDeclaration, classFile, method, firstLineNumber)); } else { + ClassFileMethodDeclaration methodDeclaration; SignatureParser.MethodTypes methodTypes = parser.parseMethodSignature(method); - list.add(new ClassFileMethodDeclaration( + list.add(methodDeclaration = new ClassFileMethodDeclaration( bodyDeclaration, classFile, method, annotationReferences, name, methodTypes.typeParameters, methodTypes.returned, methodTypes.parameters, methodTypes.exceptions, defaultAnnotationValue, firstLineNumber)); + if ((classFile.getAccessFlags() & Constants.ACC_INTERFACE) != 0) { + if (methodDeclaration.getFlags() == Constants.ACC_PUBLIC) { + // For interfaces, add 'default' access flag on public methods + methodDeclaration.setFlags(Declaration.FLAG_PUBLIC|Declaration.FLAG_DEFAULT); + } + } } } @@ -284,7 +288,7 @@ protected ModuleDeclaration convertModuleDeclaration(ClassFile classFile) { List provides = convertModuleDeclarationServiceInfo(attributeModule.getProvides()); return new ModuleDeclaration( - attributeModule.getFlags(), attributeModule.getName(), attributeModule.getName(), + attributeModule.getFlags(), classFile.getInternalTypeName(), attributeModule.getName(), attributeModule.getVersion(), requires, exports, opens, uses, provides); } diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index e0699538..7ef381d7 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -334,6 +334,96 @@ public void testJdk170While() throws Exception { assertTrue(source.indexOf("/* ") == -1); } + @Test + public void testJdk901While() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/While"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 15]", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23]", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42]", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("[ 113: 0]", "continue;"))); + assertTrue(source.matches(PatternMaker.make("[ 128: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 158: 0]", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232]", "while (++i < 10)"))); + assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); + assertFalse(source.matches(PatternMaker.make("[ 348: 0]", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348]", "continue;"))); + assertTrue(source.matches(PatternMaker.make("[ 404: 404]", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk1002While() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/While"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 15]", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23]", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42]", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("[ 113: 0]", "continue;"))); + assertTrue(source.matches(PatternMaker.make("[ 128: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("[ 158: 0]", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232]", "while (++i < 10)"))); + assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); + assertFalse(source.matches(PatternMaker.make("[ 348: 0]", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348]", "continue;"))); + assertTrue(source.matches(PatternMaker.make("[ 404: 404]", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + @Test public void testJdk170DoWhile() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); @@ -374,6 +464,86 @@ public void testJdk170DoWhile() throws Exception { assertTrue(source.indexOf("/* ") == -1); } + @Test + public void testJdk901DoWhile() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/DoWhile"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 24]", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32]", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44]", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46]", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72]", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77]", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79]", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98]", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108]", "while (i-- > 0.0F);"))); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk1002DoWhile() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/DoWhile"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 24]", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32]", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44]", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46]", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72]", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77]", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79]", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98]", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108]", "while (i-- > 0.0F);"))); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + @Test public void testJdk170BreakContinue() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); @@ -1945,6 +2115,98 @@ public void testJdk170Enum() throws Exception { assertTrue(source.indexOf("/* ") == -1); } + @Test + public void testJdk901Enum() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Enum"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 5]", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + + assertTrue(source.matches(PatternMaker.make(": 9]", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17]", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20]", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.indexOf("this.mass = mass;") != -1); + assertTrue(source.matches(PatternMaker.make(": 27]", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37]", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49]", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50]", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51]", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52]", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + + assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); + + assertTrue(source.indexOf("public static final enum") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk1002Enum() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Enum"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 5]", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + + assertTrue(source.matches(PatternMaker.make(": 9]", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17]", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20]", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.indexOf("this.mass = mass;") != -1); + assertTrue(source.matches(PatternMaker.make(": 27]", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37]", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49]", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50]", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51]", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52]", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + + assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); + + assertTrue(source.indexOf("public static final enum") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + @Test public void testJdk118Basic() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); @@ -2021,6 +2283,84 @@ public void testJdk142Basic() throws Exception { assertTrue(source.indexOf("/* ") == -1); } + @Test + public void testJdk901Basic() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 18]", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19]", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); + assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + + @Test + public void testJdk1002Basic() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make(": 18]", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19]", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); + assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + @Test public void testJdk180Lambda() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); @@ -2066,6 +2406,45 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.indexOf("/* ") == -1); } + @Test + public void testJdk901InterfaceWithDefaultMethods() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", "org/jd/core/test/InterfaceWithDefaultMethods"); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.matches(PatternMaker.make("public interface InterfaceWithDefaultMethods"))); + assertTrue(source.matches(PatternMaker.make("void setTime(int paramInt1, int paramInt2, int paramInt3);"))); + assertTrue(source.matches(PatternMaker.make("LocalDateTime getLocalDateTime();"))); + assertTrue(source.matches(PatternMaker.make("static ZoneId getZoneId(String zoneString)"))); + assertTrue(source.matches(PatternMaker.make(": 24]", "return unsafeGetZoneId(zoneString);"))); + assertTrue(source.matches(PatternMaker.make(": 26]", "System.err.println(\"Invalid time zone: \" + zoneString + \"; using default time zone instead.\");"))); + assertTrue(source.matches(PatternMaker.make(": 27]", "return ZoneId.systemDefault();"))); + assertTrue(source.matches(PatternMaker.make(": 32]", "default ZonedDateTime getZonedDateTime(String zoneString) { return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString)); }"))); + assertTrue(source.matches(PatternMaker.make(": 36]", "private static ZoneId unsafeGetZoneId(String zoneString) { return ZoneId.of(zoneString); }"))); + assertTrue(source.matches(PatternMaker.make(": 40]", "private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId) { return ZonedDateTime.of(localDateTime, zoneId); }"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf("/* ") == -1); + } + protected void printSource(String source) { System.out.println("- - - - - - - - "); System.out.println(source); diff --git a/src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java b/src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java index 29d7d36f..5c9efa4e 100644 --- a/src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java +++ b/src/test/resources/java/org/jd/core/test/InterfaceWithDefaultMethods.java @@ -15,21 +15,28 @@ public interface InterfaceWithDefaultMethods { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); - void setDateAndTime(int day, int month, int year, - int hour, int minute, int second); + void setDateAndTime(int day, int month, int year, int hour, int minute, int second); + LocalDateTime getLocalDateTime(); - static ZoneId getZoneId (String zoneString) { + static ZoneId getZoneId(String zoneString) { try { - return ZoneId.of(zoneString); + return unsafeGetZoneId(zoneString); } catch (DateTimeException e) { - System.err.println("Invalid time zone: " + zoneString + - "; using default time zone instead."); + System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } default ZonedDateTime getZonedDateTime(String zoneString) { - return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); + return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString)); + } + + private static ZoneId unsafeGetZoneId(String zoneString) throws DateTimeException { + return ZoneId.of(zoneString); + } + + private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId) { + return ZonedDateTime.of(localDateTime, zoneId); } } \ No newline at end of file diff --git a/src/test/resources/zip/data-java-jdk-10.0.2.zip b/src/test/resources/zip/data-java-jdk-10.0.2.zip index cc2e8a1eecf4f0285828f055eb1b1fc840cca09a..31b48461320f07f38d4999b2f53b40cf2dab9b50 100644 GIT binary patch delta 1002 zcmVT`3wNb?0{{T12LJ#vldu~UlWRC3f0b0(a?>yrJpyXe zU#I~XXC2B_J$u%{FPVNKbegsm30j+C(#2KW*_qr(Ff9{2!0is8yO4QM-yDr(T03?Lk1aU*kE$l#u=d-%IA?mWa?ezvBoTa$30D= zw?tVbV={Q9q^JiBhszl-;&R4o>Nu1$)xT{s92u>tseqV^jZlgQoz@!>Pw_Vqos?4g zXFLv#oF6iJ_WVWj$NR1KzG&-ENn$K~B<{>5vGjyNi1kg)fBm`pyq&Xd%mWX)nI8X# z_!r?O4gEGu7{(hap7CY_&sVYVv`Dm9ms-Tr+!xP7{dPi3^G>Ai3;k9F3E34pGU3zW zcDHhc#axJQvbbTQHWq3D=rxp@>$Dl1x|AZWMLbCa)!@@&=v|Jid3U%BB9V+{hSlB- zS2CRXf6x|v;IA9YN1-~_OHt!d)C{$#+IYcm=$~R^*gF_!QQBA!^IN-yKF%ltv~JAT zO(>bwj6ETS&E$isPy1P{qCYTFSpb`Fe8%d^cdP-vU}yo>JfT415MfqhJMBwGNxLEJ zfQ6kT@1h;q6T%{YJ4t4#yc>IH-Aj)JcFQI`f1}Ih=6-9$XZ#i`m2a>ajxJ#BR}9b7 z(W=yumD0Ewc?QLP9H5nUDLH*laM0*dLXTu)F+_7L*jnq+;#bcp1W^ql$) zvmqxJ5e@@g&`y2}ccpm)005{5lSVjF7AxbMdM6~+0W0I1dM6~+0e4rhz+l^xt~e|L YgeQ}+8xxaICkvDMI5Y-vGXMYp0Cf!D(EtDd delta 899 zcmV-}1AP3KbF^}>#Ul{~r*BTMRqN#z0{{S#1^@suldu~Ulg>CHf0b0*QWHTCJ;Nmn zAzTayDvD77!*#u)5^oSdq5-T5g;n}A><+N7*-7nADDg}D49W)!dGG`LD9fJgLV!RD zv$dJ&p3|q#^z`hXzlXm8OkpLCdl)n@)QVx;Pm*sej&V$A_hcL5F!kSqI3D7WfyV}( zFc^VQt4>ic#L~H3e{N(gbj@)^u8wFnnI0!sY(-NPe5|a#N9M zo?6UMFa>;;p2*n@!|4#{a&OZtDBtlmGbdw190fIHrA^G8dB+pW<>I>VSNXb2o@9l7 zjr)$aBPXNx)(M)U?DJnOQBscdh%x?+xWkmhQX_*9?FGfHf1M>>idefM;dXVW6PM6` z4A6;lqfPZ3g2hA8kX3R z=0_^IqQVPa%)~K|1%|1dx656}PHDoFKIQ2Y%cRNy9Zt#))l}C~jz`Sgo@D4N@*RH4NpQDRzQb}8`N5an|TBBAAe=7TnYQ@l#KKB;%Refg~aUp%- zjjJK5)1e05=|lg(Fj&>;c)M~(L~_IWEO1Lnf6u@YeK7J;?vzUmiJa#NKkM=!5LC49 z$9t`Egk7-6J=+z*U>KOGEy+cJt9vDJ4*X00Y)@rIYALeZbqkKtn_OlXx|BACf%>=@ z-A%MXfB#}lR06aEG5)B)S{WeQO7)B*ZoWC~F6 ZlMy*A0wE`pu^SVUQaL{c4l@7%003bes2>0T diff --git a/src/test/resources/zip/data-java-jdk-9.0.1.zip b/src/test/resources/zip/data-java-jdk-9.0.1.zip index f062b95e58375a526d5249b2cdd578659799ecc4..fed95cdf7f87f16394b91b1d96c27d71dcc2009d 100644 GIT binary patch delta 995 zcmV<9104LOa*1=W!Xpj?UC>U_Zx;-C0{{T12b0hvI)B-6(=Zf00&3G>2m~lQ7$}ei zsM)u$rxXHVP1&D>troYAl(7{C_!2&&!vho^_y9hN;mS4*ZPE-RV@p@}+;dm?=dbTS z0G!3kb#QRZ#_?f{!zpE+YyszR-smov*G2QXWX`GuT*eg}S8ZHluoI!D!j@pL z%Jq7E?0;EyG{H3;ZOC^wWRPKo4JL$D@rruQ^Ys~U@+|wj_OO#bICWBW> zih96sxSRnaE@!-^jzc+9{o6LfkG6Mve-Uod&~L+p zVZ5Q@8E-c5d=(2%i$r^MsYN`^eepchZzsew??n2(&~H_ckX^AO6Fx0&cPm#|%!T+S z%PZEqroI4=9abxV@AVz3#2DHq^bq62qxYq+O!9)X9ohsdub5_lb*c zd)r8nq`>5FYhWfO_8rKbv7QG#yw>i?Ya%+J2fYA?^(K& z+}A4pVB&ATDgpyg!*b`#d zOg^akw4cQ)`U4}C1+e+XXRNM##~R=Zh8AGW6AB~_5oR^E)4pVsv>U<>SlCJOF4~bj zAuRH@lVq04yRnDXz4TaMw`|fgx_@kL?zcvK#&5Aw`39Te=mOS$#qc~Gtx6qPDUF+v zXHe|N0a|I7lGFDD2aPTz^hh=qLzGBiIn8KF<79w5ve7g%X7V>5fjq7Wlc}*gdTasf zmh+TT9ydc|;iS96IFjluLX4#hmDKVmrf4mY?g^fuN!BM!he$q2&#B)~OS2#+3K0$i zUC>U_Zx;-C0{{T12a`BBQWnTDE_x><)d9#cE_x><)d6wky}w}Flb|>(0)Z!!0TdIH RO(zSJ>^L+AV>18%006AN-K_us delta 885 zcmV-*1B(2KbEa~z!Xpj^r*BSbU_JL10{{S#29wYuI)B?z6G0F?!zBwbTnq>*ictZ> zb-jT~yg>ko2Cym=R_W8QJHWzbC$&4F#4qtPC?723!4L4GEPJvG0Rkz^)@G)APM<#0 z)3bm69{vU}iIq6+W5B>*D~9kONxsoI#xSnk6IT$2ssA3v@d%F%JTdT;!3cy}b&7%^ zmd@pJ!+&d`YmO^&wMVlV&kixI8WX`fH-*Yei@O>TF88H}^V@uvn~F^H)MAE$Dd4m8 zM9yXyN{2v~dz)rK`Hr`lIT;(`D5xnbZDQ`oJDylB7uSWq%GX`;BrEi5+;_AcIT^jT zPtY7?pZ{u!l5(U+jPY;89i}9f8X1IWD=2R5EPwG*#M&7Nx2roHzl8o{xZZ}^asq~l zy!1ECZQHb@FH9u@W#&93{0(l2PmbD}6C1qjswJVeq#bCn1zGkjvEXPOsXEvRo!h`< z0#oRwlc-Yz1J4q8ju*7CSt(VZd|rxJI%1e^K_-EhcxB*q0&nm(ff>vua23e}y3lPP ztABIMF^v7sUMN|$U@Pm}!cyd_syu3p2DxzxTG$JeC^9q(-)FcMme`TzM=H6Z!V6x^ z#4(QrhN+yl%U#D#X~L8~<>?g5q{;yuPRb6|RM%3DN6g%wVCXIK9g&ru#g!ILvp{iA z1sAqyZOe3>ql<1*Nn5T*!p|dGqgD$l`+tjS#n7ET_ZIY4ePp$6XR zL;t`qP}S*pyK+ZFa>M#8a7#&l&%hFWF!ECFluHbWoaYHY>+&EFRJ8BMd#!SWU9iYK z+ZDk;7?`Oo$wh&ydnIuW{7e39Pi2N{DYD#k3y#v8TxJ-&ls1O``nVX~O&ncbm~#x8bY+{iv#Kcns1|l9-wFB0Bk@11C1kxXaats`2ewfLV?U?!Zf0X z=1ILsyv@WJBi1B6y*i!{+P;n(6r=5%=%ewLRs=S0&^mn#(I4fVjq Date: Sun, 16 Jun 2019 12:12:48 +0200 Subject: [PATCH 027/211] Add string concatenation in Java 9 support --- .../org/jd/core/v1/api/printer/Printer.java | 30 ++--- .../core/v1/model/classfile/ConstantPool.java | 10 +- .../expression/StringConstantExpression.java | 2 + .../util/ByteCodeParser.java | 60 +++++---- .../util/ByteCodeWriter.java | 14 +- .../util/ControlFlowGraphMaker.java | 4 +- .../util/CreateConcatStringUtil.java | 58 --------- .../util/StringConcatenationUtil.java | 120 ++++++++++++++++++ .../visitor/InitInstanceFieldVisitor.java | 53 +++----- .../classfile/ClassFileDeserializer.java | 40 +++--- .../visitor/CompilationUnitVisitor.java | 14 +- 11 files changed, 240 insertions(+), 165 deletions(-) delete mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java diff --git a/src/main/java/org/jd/core/v1/api/printer/Printer.java b/src/main/java/org/jd/core/v1/api/printer/Printer.java index e71db4f1..4f30d48a 100644 --- a/src/main/java/org/jd/core/v1/api/printer/Printer.java +++ b/src/main/java/org/jd/core/v1/api/printer/Printer.java @@ -9,7 +9,13 @@ public interface Printer { - int UNKNOWN_LINE_NUMBER = 0; + void start(int maxLineNumber, int majorVersion, int minorVersion); + void end(); + + void printText(String text); + void printNumericConstant(String constant); + void printStringConstant(String constant, String ownerInternalName); + void printKeyword(String keyword); // Declaration & reference types int TYPE = 1; @@ -19,30 +25,24 @@ public interface Printer { int PACKAGE = 5; int MODULE = 6; - // Marker types - int COMMENT = 1; - int JAVADOC = 2; - int ERROR = 3; - int IMPORT_STATEMENTS = 4; - - void start(int maxLineNumber, int majorVersion, int minorVersion); - void end(); - - void printText(String text); - void printNumericConstant(String constant); - void printStringConstant(String constant, String ownerInternalName); - void printKeyword(String keyword); - void printDeclaration(int type, String internalTypeName, String name, String descriptor); void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName); void indent(); void unindent(); + int UNKNOWN_LINE_NUMBER = 0; + void startLine(int lineNumber); void endLine(); void extraLine(int count); + // Marker types + int COMMENT = 1; + int JAVADOC = 2; + int ERROR = 3; + int IMPORT_STATEMENTS = 4; + void startMarker(int type); void endMarker(int type); } diff --git a/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java b/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java index 330dbaf3..326bda79 100644 --- a/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java +++ b/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java @@ -22,13 +22,19 @@ public T getConstant(int index) { return (T)constants[index]; } - public String getConstantTypeName(int classIndex) { - ConstantClass cc = (ConstantClass)constants[classIndex]; + public String getConstantTypeName(int index) { + ConstantClass cc = (ConstantClass)constants[index]; ConstantUtf8 cutf8 = (ConstantUtf8)constants[cc.getNameIndex()]; return cutf8.getValue(); } public String getConstantString(int index) { + ConstantString cString = (ConstantString)constants[index]; + ConstantUtf8 cutf8 = (ConstantUtf8)constants[cString.getStringIndex()]; + return cutf8.getValue(); + } + + public String getConstantUtf8(int index) { ConstantUtf8 cutf8 = (ConstantUtf8)constants[index]; return cutf8.getValue(); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java index c8b6fead..93156fd3 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java @@ -11,6 +11,8 @@ import org.jd.core.v1.model.javasyntax.type.Type; public class StringConstantExpression extends AbstractLineNumberExpression { + public static final StringConstantExpression EMPTY_STRING = new StringConstantExpression(""); + protected String string; public StringConstantExpression(String string) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 832e9e78..dd933e82 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -727,8 +727,8 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ot = objectTypeMaker.make(typeName); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - name = constants.getConstantString(constantNameAndType.getNameIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); BaseExpression parameters = getParameters(statements, stack, descriptor); Type returnedType = signatureParser.parseReturnedType(descriptor); @@ -777,7 +777,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau "toString".equals(name) && "()Ljava/lang/String;".equals(descriptor)) { typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); if ("java/lang/StringBuilder".equals(typeName) || "java/lang/StringBuffer".equals(typeName)) { - stack.push(CreateConcatStringUtil.create(expression1, lineNumber, typeName)); + stack.push(StringConcatenationUtil.create(expression1, lineNumber, typeName)); break; } } @@ -1043,7 +1043,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in break; case Constant.CONSTANT_String: int stringIndex = ((ConstantString)constant).getStringIndex(); - stack.push(new StringConstantExpression(lineNumber, constants.getConstantString(stringIndex))); + stack.push(new StringConstantExpression(lineNumber, constants.getConstantUtf8(stringIndex))); break; } } @@ -1273,27 +1273,39 @@ private void parseInvokeDynamic(Statements statements, DefaultStack stack, ConstantPool constan ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); if (name.equals("TYPE") && typeName.startsWith("java/lang/")) { switch (typeName) { @@ -1653,7 +1665,7 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan } } - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); ObjectType ot = objectTypeMaker.make(typeName); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); @@ -1665,8 +1677,8 @@ private void parsePutStatic(Statements statements, DefaultStack stac String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ObjectType ot = objectTypeMaker.make(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); Expression valueRef = stack.pop(); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); @@ -1679,8 +1691,8 @@ private void parseGetField(DefaultStack stack, ConstantPool constant String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ObjectType ot = objectTypeMaker.make(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); Expression objectRef = stack.pop(); stack.push(new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor)); @@ -1691,8 +1703,8 @@ private void parsePutField(Statements statements, DefaultStack stack String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ObjectType ot = objectTypeMaker.make(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); Expression valueRef = stack.pop(); Expression objectRef = stack.pop(); @@ -1942,12 +1954,12 @@ public static boolean isAssertCondition(String internalTypeName, BasicBlock basi ConstantPool constants = method.getConstants(); ConstantMemberRef constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); if (! "$assertionsDisabled".equals(name)) return false; - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); if (! "Z".equals(descriptor)) return false; @@ -2309,7 +2321,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 182: case 183: // INVOKEVIRTUAL, INVOKESPECIAL constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= 1 + countMethodParameters(descriptor); if (descriptor.charAt(descriptor.length()-1) != 'V') { @@ -2319,7 +2331,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 184: // INVOKESTATIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= countMethodParameters(descriptor); if (descriptor.charAt(descriptor.length()-1) != 'V') { @@ -2329,7 +2341,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 185: // INVOKEINTERFACE constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= 1 + countMethodParameters(descriptor); offset += 2; // Skip 'count' and one byte @@ -2340,7 +2352,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 186: // INVOKEDYNAMIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= countMethodParameters(descriptor); offset += 2; // Skip 2 bytes diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java index 7ca88b75..47531a14 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java @@ -204,24 +204,24 @@ protected static void writeByteCode(String linePrefix, StringBuilder sb, Constan ConstantMemberRef constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); sb.append(" ").append(typeName).append('.').append(name).append(" : ").append(descriptor); break; case 180: case 181: case 182: case 183: case 184: // GETFIELD, PUTFIELD, INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - name = constants.getConstantString(constantNameAndType.getNameIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); sb.append(" ").append(name).append(" : ").append(descriptor); break; case 185: case 186: // INVOKEINTERFACE, INVOKEDYNAMIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - name = constants.getConstantString(constantNameAndType.getNameIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); sb.append(" ").append(name).append(" : ").append(descriptor); @@ -302,7 +302,7 @@ protected static void writeLDC(StringBuilder sb, ConstantPool constants, Constan case Constant.CONSTANT_String: sb.append(" '"); int stringIndex = ((ConstantString) constant).getStringIndex(); - String str = constants.getConstantString(stringIndex); + String str = constants.getConstantUtf8(stringIndex); for (char c : str.toCharArray()) { switch (c) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java index 0a2b9fec..b85f70d1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java @@ -98,7 +98,7 @@ public static ControlFlowGraph make(Method method) { case 182: case 183: case 184: // INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC ConstantMemberRef constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); if (descriptor.charAt(descriptor.length()-1) == 'V') { lastStatementOffset = offset; } @@ -106,7 +106,7 @@ public static ControlFlowGraph make(Method method) { case 185: case 186: // INVOKEINTERFACE, INVOKEDYNAMIC constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); offset += 2; // Skip 2 bytes if (descriptor.charAt(descriptor.length()-1) == 'V') { lastStatementOffset = offset; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java deleted file mode 100644 index 3c753dc4..00000000 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2008-2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.service.converter.classfiletojavasyntax.util; - -import org.jd.core.v1.model.javasyntax.expression.BinaryOperatorExpression; -import org.jd.core.v1.model.javasyntax.expression.Expression; -import org.jd.core.v1.model.javasyntax.expression.MethodInvocationExpression; -import org.jd.core.v1.model.javasyntax.expression.NewExpression; -import org.jd.core.v1.model.javasyntax.type.ObjectType; - -public class CreateConcatStringUtil { - - public static Expression create(Expression expression, int lineNumber, String typeName) { - if (expression.getClass() == MethodInvocationExpression.class) { - MethodInvocationExpression mie = (MethodInvocationExpression)expression; - - if ("append".equals(mie.getName()) && (mie.getParameters() != null) && !mie.getParameters().isList()) { - Expression concatenatedStringExpression = mie.getParameters().getFirst(); - - Expression expr = mie.getExpression(); - - while (expr.getClass() == MethodInvocationExpression.class) { - mie = (MethodInvocationExpression)expr; - - if (("append".equals(mie.getName()) == false) || (mie.getParameters() == null) || mie.getParameters().isList()) - break; - - concatenatedStringExpression = new BinaryOperatorExpression(mie.getLineNumber(), ObjectType.TYPE_STRING, (Expression)mie.getParameters(), "+", concatenatedStringExpression, 4); - expr = mie.getExpression(); - } - - if (expr.getClass() == NewExpression.class) { - NewExpression ne = (NewExpression)expr; - String internalTypeName = ne.getType().getDescriptor(); - - if ("Ljava/lang/StringBuilder;".equals(internalTypeName) || "Ljava/lang/StringBuffer;".equals(internalTypeName)) { - if (ne.getParameters() == null) { - return concatenatedStringExpression; - } else if (!ne.getParameters().isList()) { - expression = ne.getParameters().getFirst(); - - if (expression.getType() == ObjectType.TYPE_STRING) { - return new BinaryOperatorExpression(ne.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", concatenatedStringExpression, 4); - } - } - } - } - } - } - - return new MethodInvocationExpression(lineNumber, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;"); - } -} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java new file mode 100644 index 00000000..5a8f477a --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.util; + +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.util.DefaultList; + +import java.util.StringTokenizer; + +public class StringConcatenationUtil { + + public static Expression create(Expression expression, int lineNumber, String typeName) { + if (expression.getClass() == MethodInvocationExpression.class) { + MethodInvocationExpression mie = (MethodInvocationExpression) expression; + + if ("append".equals(mie.getName()) && (mie.getParameters() != null) && !mie.getParameters().isList()) { + Expression concatenatedStringExpression = mie.getParameters().getFirst(); + Expression expr = mie.getExpression(); + + while (expr.getClass() == MethodInvocationExpression.class) { + mie = (MethodInvocationExpression) expr; + + if (("append".equals(mie.getName()) == false) || (mie.getParameters() == null) || mie.getParameters().isList()) { + break; + } + + concatenatedStringExpression = new BinaryOperatorExpression(mie.getLineNumber(), ObjectType.TYPE_STRING, (Expression) mie.getParameters(), "+", concatenatedStringExpression, 4); + expr = mie.getExpression(); + } + + if (expr.getClass() == NewExpression.class) { + NewExpression ne = (NewExpression) expr; + String internalTypeName = ne.getType().getDescriptor(); + + if ("Ljava/lang/StringBuilder;".equals(internalTypeName) || "Ljava/lang/StringBuffer;".equals(internalTypeName)) { + if (ne.getParameters() == null) { + return concatenatedStringExpression; + } + if (!ne.getParameters().isList()) { + expression = ne.getParameters().getFirst(); + + if (expression.getType() == ObjectType.TYPE_STRING) { + return new BinaryOperatorExpression(ne.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", concatenatedStringExpression, 4); + } + } + } + } + } + } + + return new MethodInvocationExpression(lineNumber, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;"); + } + + public static Expression create(String recipe, BaseExpression parameters) { + StringTokenizer st = new StringTokenizer(recipe, "\u0001", true); + + if (st.hasMoreTokens()) { + String token = st.nextToken(); + Expression expression = token.equals("\u0001") ? createFirstStringConcatenationItem(parameters.getFirst()) : new StringConstantExpression(token); + + if (parameters.isList()) { + DefaultList list = parameters.getList(); + int index = 0; + + while (st.hasMoreTokens()) { + token = st.nextToken(); + Expression e = token.equals("\u0001") ? list.get(index++) : new StringConstantExpression(token); + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", e, 6); + } + } else { + while (st.hasMoreTokens()) { + token = st.nextToken(); + Expression e = token.equals("\u0001") ? parameters.getFirst() : new StringConstantExpression(token); + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", e, 6); + } + } + + return expression; + } else { + return StringConstantExpression.EMPTY_STRING; + } + } + + public static Expression create(BaseExpression parameters) { + if (parameters.isList()) { + DefaultList list = parameters.getList(); + + switch (list.size()) { + case 0: + return StringConstantExpression.EMPTY_STRING; + case 1: + return createFirstStringConcatenationItem(parameters.getFirst()); + default: + Expression expression = createFirstStringConcatenationItem(parameters.getFirst()); + + for (int i = 1, len = list.size(); i < len; i++) { + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", list.get(i), 6); + } + + return expression; + } + } else { + return createFirstStringConcatenationItem(parameters.getFirst()); + } + } + + private static Expression createFirstStringConcatenationItem(Expression expression) { + if (!expression.getType().equals(ObjectType.TYPE_STRING)) { + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, StringConstantExpression.EMPTY_STRING, "+", expression, 6); + } + + return expression; + } +} \ No newline at end of file diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java index f403df69..1c1c3fb5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java @@ -24,10 +24,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFieldDeclaration; import org.jd.core.v1.util.DefaultList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.ListIterator; +import java.util.*; public class InitInstanceFieldVisitor extends AbstractJavaSyntaxVisitor { protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); @@ -87,7 +84,7 @@ public void visit(ConstructorDeclaration declaration) { if (cfcd.getStatements().getClass() == Statements.class) { Statements statements = (Statements) cfcd.getStatements(); ListIterator iterator = statements.listIterator(); - Expression superConstructorCall = searchSuperConstructorCall(iterator); + SuperConstructorInvocationExpression superConstructorCall = searchSuperConstructorCall(iterator); if (superConstructorCall != null) { String internalTypeName = cfcd.getClassFile().getInternalTypeName(); @@ -95,7 +92,8 @@ public void visit(ConstructorDeclaration declaration) { datas.add(new Data(cfcd, statements, iterator.nextIndex())); if (datas.size() == 1) { - initPutFields(internalTypeName, cfcd, iterator); + int firstLineNumber = superConstructorCall.getDescriptor().equals("()V") ? Printer.UNKNOWN_LINE_NUMBER : superConstructorCall.getLineNumber(); + initPutFields(internalTypeName, firstLineNumber, iterator); } else { filterPutFields(internalTypeName, iterator); } @@ -124,7 +122,7 @@ public void visit(LocalVariableReferenceExpression expression) { containsLocalVariableReference = true; } - protected Expression searchSuperConstructorCall(ListIterator iterator) { + protected SuperConstructorInvocationExpression searchSuperConstructorCall(ListIterator iterator) { while (iterator.hasNext()) { Statement statement = iterator.next(); @@ -133,7 +131,7 @@ protected Expression searchSuperConstructorCall(ListIterator iterator Class clazz = expression.getClass(); if (clazz == SuperConstructorInvocationExpression.class) { - return expression; + return (SuperConstructorInvocationExpression)expression; } if (clazz == ConstructorInvocationExpression.class) { @@ -145,30 +143,9 @@ protected Expression searchSuperConstructorCall(ListIterator iterator return null; } - protected void initPutFields(String internalTypeName, ClassFileConstructorDeclaration cfcd, ListIterator iterator) { - Method method = cfcd.getMethod(); + protected void initPutFields(String internalTypeName, int firstLineNumber, ListIterator iterator) { HashSet fieldNames = new HashSet<>(); - int lineNumberBefore = 0; - int lineNumberAfter = 0; Expression expression = null; - AttributeCode attributeCode = method.getAttribute("Code"); - - if (attributeCode != null) { - AttributeLineNumberTable lineNumberTable = attributeCode.getAttribute("LineNumberTable"); - - if (lineNumberTable != null) { - LineNumber[] lineNumbers = lineNumberTable.getLineNumberTable(); - lineNumberBefore = lineNumbers[0].getLineNumber(); - lineNumberAfter = lineNumbers[lineNumbers.length - 1].getLineNumber(); - - for (ClassFileConstructorOrMethodDeclaration cfcomd : cfcd.getBodyDeclaration().getMethodDeclarations()) { - if ((cfcomd.getFirstLineNumber() > lineNumberBefore) && (cfcomd.getFirstLineNumber() < lineNumberAfter)) { - lineNumberAfter = Printer.UNKNOWN_LINE_NUMBER; - break; - } - } - } - } while (iterator.hasNext()) { Statement statement = iterator.next(); @@ -210,15 +187,27 @@ protected void initPutFields(String internalTypeName, ClassFileConstructorDeclar putFields.add(cfboe); fieldNames.add(fieldName); + expression = null; } - if ((lineNumberAfter != Printer.UNKNOWN_LINE_NUMBER) && (expression != null) && (expression.getLineNumber() != lineNumberAfter)) { + int lastLineNumber; + + if (expression == null) { + lastLineNumber = (firstLineNumber == Printer.UNKNOWN_LINE_NUMBER) ? Printer.UNKNOWN_LINE_NUMBER : firstLineNumber+1; + } else { + lastLineNumber = expression.getLineNumber(); + } + + if (firstLineNumber < lastLineNumber) { Iterator ite = putFields.iterator(); while (ite.hasNext()) { int lineNumber = ite.next().getLineNumber(); - if ((lineNumberBefore <= lineNumber) && (lineNumber <= lineNumberAfter)) { + if ((firstLineNumber <= lineNumber) && (lastLineNumber <= lastLineNumber)) { + if (lastLineNumber == lastLineNumber) { + lastLineNumber++; + } ite.remove(); } } diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 5b21ed14..7bf3fc6a 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -191,8 +191,8 @@ protected Field[] loadFields(ClassFileReader reader, ConstantPool constants) { int signatureIndex = reader.readUnsignedShort(); HashMap attributes = loadAttributes(reader, constants); - String name = constants.getConstantString(nameIndex); - String signature = constants.getConstantString(signatureIndex); + String name = constants.getConstantUtf8(nameIndex); + String signature = constants.getConstantUtf8(signatureIndex); fields[i] = new Field(accessFlags, name, signature, attributes); } @@ -213,8 +213,8 @@ protected Method[] loadMethods(ClassFileReader reader, ConstantPool constants) { int signatureIndex = reader.readUnsignedShort(); HashMap attributes = loadAttributes(reader, constants); - String name = constants.getConstantString(nameIndex); - String signature = constants.getConstantString(signatureIndex); + String name = constants.getConstantUtf8(nameIndex); + String signature = constants.getConstantUtf8(signatureIndex); methods[i] = new Method(accessFlags, name, signature, attributes, constants); } @@ -284,7 +284,7 @@ protected HashMap loadAttributes(ClassFileReader reader, Cons attributes.put(name, new AttributeModule( constants.getConstantTypeName(reader.readUnsignedShort()), reader.readUnsignedShort(), - constants.getConstantString(reader.readUnsignedShort()), + constants.getConstantUtf8(reader.readUnsignedShort()), loadModuleInfos(reader, constants), loadPackageInfos(reader, constants), loadPackageInfos(reader, constants), @@ -310,12 +310,12 @@ protected HashMap loadAttributes(ClassFileReader reader, Cons case "Signature": if (attributeLength != 2) throw new ClassFileFormatException("Invalid attribute length"); - attributes.put(name, new AttributeSignature(constants.getConstantString(reader.readUnsignedShort()))); + attributes.put(name, new AttributeSignature(constants.getConstantUtf8(reader.readUnsignedShort()))); break; case "SourceFile": if (attributeLength != 2) throw new ClassFileFormatException("Invalid attribute length"); - attributes.put(name, new AttributeSourceFile(constants.getConstantString(reader.readUnsignedShort()))); + attributes.put(name, new AttributeSourceFile(constants.getConstantUtf8(reader.readUnsignedShort()))); break; case "Synthetic": if (attributeLength != 0) @@ -346,17 +346,17 @@ protected ElementValue loadElementValue(ClassFileReader reader, ConstantPool con return new ElementValuePrimitiveType(type, constValue); case 'e': int typeNameIndex = reader.readUnsignedShort(); - String typeName = constants.getConstantString(typeNameIndex); + String typeName = constants.getConstantUtf8(typeNameIndex); int constNameIndex = reader.readUnsignedShort(); - String constName = constants.getConstantString(constNameIndex); + String constName = constants.getConstantUtf8(constNameIndex); return new ElementValueEnumConstValue(typeName, constName); case 'c': int classInfoIndex = reader.readUnsignedShort(); - String classInfo = constants.getConstantString(classInfoIndex); + String classInfo = constants.getConstantUtf8(classInfoIndex); return new ElementValueClassInfo(classInfo); case '@': int typeIndex = reader.readUnsignedShort(); - typeName = constants.getConstantString(typeIndex); + typeName = constants.getConstantUtf8(typeIndex); return new ElementValueAnnotationValue(new Annotation(typeName, loadElementValuePairs(reader, constants))); case '[': return new ElementValueArrayValue(loadElementValues(reader, constants)); @@ -374,7 +374,7 @@ protected ElementValuePair[] loadElementValuePairs(ClassFileReader reader, Const for (int i=0; i < count; i++) { int elementNameIndex = reader.readUnsignedShort(); - String elementName = constants.getConstantString(elementNameIndex); + String elementName = constants.getConstantUtf8(elementNameIndex); pairs[i] = new ElementValuePair(elementName, loadElementValue(reader, constants)); } @@ -487,7 +487,7 @@ protected InnerClass[] loadInnerClasses(ClassFileReader reader, ConstantPool con String innerTypeName = constants.getConstantTypeName(innerTypeIndex); String outerTypeName = (outerTypeIndex == 0) ? null : constants.getConstantTypeName(outerTypeIndex); - String innerName = (innerNameIndex == 0) ? null : constants.getConstantString(innerNameIndex); + String innerName = (innerNameIndex == 0) ? null : constants.getConstantUtf8(innerNameIndex); innerClasses[i] = new InnerClass(innerTypeName, outerTypeName, innerName, innerAccessFlags); } @@ -509,8 +509,8 @@ protected LocalVariable[] loadLocalVariables(ClassFileReader reader, ConstantPoo int descriptorIndex = reader.readUnsignedShort(); int index = reader.readUnsignedShort(); - String name = constants.getConstantString(nameIndex); - String descriptor = constants.getConstantString(descriptorIndex); + String name = constants.getConstantUtf8(nameIndex); + String descriptor = constants.getConstantUtf8(descriptorIndex); localVariables[i] = new LocalVariable(startPc, length, name, descriptor, index); } @@ -532,8 +532,8 @@ protected LocalVariableType[] loadLocalVariableTypes(ClassFileReader reader, Con int descriptorIndex = reader.readUnsignedShort(); int index = reader.readUnsignedShort(); - String name = constants.getConstantString(nameIndex); - String descriptor = constants.getConstantString(descriptorIndex); + String name = constants.getConstantUtf8(nameIndex); + String descriptor = constants.getConstantUtf8(descriptorIndex); localVariables[i] = new LocalVariableType(startPc, length, name, descriptor, index); } @@ -565,7 +565,7 @@ protected MethodParameter[] loadParameters(ClassFileReader reader, ConstantPool for (int i=0; i iterator = packageInfo.getModuleInfoNames().iterator(); String moduleInfoName = iterator.next(); - tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfoName.replace('.', '/'), moduleInfoName, null, null)); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, "module-info", moduleInfoName, null, null)); while (iterator.hasNext()) { tokens.add(TextToken.COMMA); tokens.add(NewLineToken.NEWLINE_1); moduleInfoName = iterator.next(); - tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfoName.replace('.', '/'), moduleInfoName, null, null)); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, "module-info", moduleInfoName, null, null)); } tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); @@ -1282,6 +1282,10 @@ protected void buildTokensForAccessFlags(int flags) { tokens.add(PROTECTED); tokens.add(TextToken.SPACE); } + if ((flags & FLAG_DEFAULT) != 0) { + tokens.add(DEFAULT); + tokens.add(TextToken.SPACE); + } if ((flags & FLAG_STATIC) != 0) { tokens.add(STATIC); tokens.add(TextToken.SPACE); From d90d4dff229a25c217a698b3f01739009710d1ff Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 21 Jun 2019 07:46:32 +0200 Subject: [PATCH 028/211] Remove all reflection 'invoke' method calls --- .../util/LoopStatementMaker.java | 46 ++++- .../util/ObjectTypeMaker.java | 16 +- .../util/ReflectionUtil.java | 135 ------------- .../util/SwitchStatementMaker.java | 191 +++++++++++++----- .../util/SynchronizedStatementMaker.java | 34 ++-- .../util/TryWithResourcesStatementMaker.java | 136 +++++++++++-- .../org/jd/core/v1/ControlFlowGraphTest.java | 54 +++-- 7 files changed, 365 insertions(+), 247 deletions(-) delete mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ReflectionUtil.java diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index 58becca1..827f2673 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -23,8 +23,6 @@ import java.util.ListIterator; import static org.jd.core.v1.model.javasyntax.statement.ContinueStatement.CONTINUE; -import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.getExpression; -import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.invokeGetter; public class LoopStatementMaker { protected static final RemoveLastContinueStatementVisitor REMOVE_LAST_CONTINUE_STATEMENT_VISITOR = new RemoveLastContinueStatementVisitor(); @@ -378,7 +376,19 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake } // String s = arr$[i$]; - boe = invokeGetter(subStatements.get(0), getExpression, BinaryOperatorExpression.class); + statement = subStatements.getFirst(); + + if (statement.getClass() != ExpressionStatement.class) { + return null; + } + + expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() != BinaryOperatorExpression.class) { + return null; + } + + boe = (BinaryOperatorExpression)expression; if ((boe.getRightExpression().getClass() != ArrayExpression.class) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getLineNumber() != condition.getLineNumber())) { return null; @@ -401,7 +411,19 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake } // arr$ = array; - boe = invokeGetter(statements.get(statementsSize-3), getExpression, BinaryOperatorExpression.class); + statement = statements.get(statementsSize-3); + + if (statement.getClass() != ExpressionStatement.class) { + return null; + } + + expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() != BinaryOperatorExpression.class) { + return null; + } + + boe = (BinaryOperatorExpression)expression; if (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) { return null; @@ -413,9 +435,21 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake Expression array = boe.getRightExpression(); // i$ = 0; - boe = invokeGetter(statements.get(statementsSize-1), getExpression, BinaryOperatorExpression.class); + statement = statements.get(statementsSize-1); + + if (statement.getClass() != ExpressionStatement.class) { + return null; + } + + expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() != BinaryOperatorExpression.class) { + return null; + } + + boe = (BinaryOperatorExpression)expression; - if ((boe == null) || (boe.getLineNumber() != lineNumber) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getRightExpression().getClass() != IntegerConstantExpression.class)) { + if ((boe.getLineNumber() != lineNumber) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getRightExpression().getClass() != IntegerConstantExpression.class)) { return null; } if ((((IntegerConstantExpression)boe.getRightExpression()).getValue() != 0) || (((ClassFileLocalVariableReferenceExpression)boe.getLeftExpression()).getLocalVariable() != syntheticIndex)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java index f74d34c4..c761c4b4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java @@ -227,14 +227,16 @@ private boolean recursiveIsAssignable(String parentInternalName, String childInt } } - for (String name : superClassAndInterfaceNames) { - if (parentInternalName.equals(name)) - return true; - } + if (superClassAndInterfaceNames != null) { + for (String name : superClassAndInterfaceNames) { + if (parentInternalName.equals(name)) + return true; + } - for (String name : superClassAndInterfaceNames) { - if (recursiveIsAssignable(parentInternalName, name)) - return true; + for (String name : superClassAndInterfaceNames) { + if (recursiveIsAssignable(parentInternalName, name)) + return true; + } } return false; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ReflectionUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ReflectionUtil.java deleted file mode 100644 index d1341154..00000000 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ReflectionUtil.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2008-2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.service.converter.classfiletojavasyntax.util; - -import org.jd.core.v1.model.javasyntax.expression.*; -import org.jd.core.v1.model.javasyntax.statement.ExpressionStatement; -import org.jd.core.v1.model.javasyntax.statement.IfElseStatement; -import org.jd.core.v1.model.javasyntax.statement.IfStatement; -import org.jd.core.v1.model.javasyntax.statement.Statements; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; - -import java.lang.reflect.Method; - -public class ReflectionUtil { - public static final Method getExpression = getGetter(ExpressionStatement.class, "getExpression"); - public static final Method getLeftExpression = getGetter(BinaryOperatorExpression.class, "getLeftExpression"); - public static final Method getRightExpression = getGetter(BinaryOperatorExpression.class, "getRightExpression"); - public static final Method getLocalVariable = getGetter(ClassFileLocalVariableReferenceExpression.class, "getLocalVariable"); - public static final Method getName = getGetter(ClassFileLocalVariableReferenceExpression.class, "getName"); - public static final Method getValue = getGetter(IntegerConstantExpression.class, "getValue"); - public static final Method getMethodReferenceExpression = getGetter(MethodReferenceExpression.class, "getExpression"); - public static final Method getIndex = getGetter(ArrayExpression.class, "getIndex"); - public static final Method getStatements = getGetter(IfStatement.class, "getStatements"); - public static final Method getFirst = getGetter(Statements.class, "getFirst"); - public static final Method getElseStatements = getGetter(IfElseStatement.class, "getElseStatements"); - public static final Method getParameters = getGetter(MethodInvocationExpression.class, "getParameters"); - - public static final Method[] getParameters_getString = { getParameters, getGetter(StringConstantExpression.class, "getString") }; - public static final Method[] getExpression_getLeftExpression_getLocalVariable = { getExpression, getLeftExpression, getLocalVariable }; - public static final Method[] getExpression_getRightExpression = { getExpression, getRightExpression}; - public static final Method[] getExpression_getLocalVariable = { getMethodReferenceExpression, getLocalVariable}; - public static final Method[] getRightExpression_getValue = {getRightExpression, getValue }; - public static final Method[] getLeftExpression_getIndex_getExpression_getName = {getLeftExpression, getIndex, getMethodReferenceExpression, getGetter(FieldReferenceExpression.class, "getName") }; - public static final Method[] getExpression_getRightExpression_getValue = { getExpression, getRightExpression, getValue }; - public static final Method[] getIndex_getExpression = { getIndex, getMethodReferenceExpression }; - public static final Method[] getStatements_getFirst = { getStatements, getFirst }; - public static final Method[] getFirst_getExpression = { getFirst, getExpression }; - public static final Method[] getElseStatements_getFirst_getExpression = { getElseStatements, getFirst, getExpression }; - - protected static final Class[] parameterTypes = {}; - - public static Object invokeGetter(Object object, Method getter) { - if (object != null) { - try { - return getter.invoke(object); - } catch (Exception e) { - assert ExceptionUtil.printStackTrace(e); - } - } - return null; - } - - public static Object invokeGetters(Object object, Method[] getters) { - try { - for (Method getter : getters) { - object = getter.invoke(object); - } - return object; - } catch (Exception e) { - assert ExceptionUtil.printStackTrace(e); - } - return null; - } - - @SuppressWarnings("unchecked") - public static T invokeGetter(Object object, Method getter, Class resultClass) { - if (object != null) { - try { - object = getter.invoke(object); - if (resultClass.isInstance(object)) - return (T)object; - } catch (Exception e) { - assert ExceptionUtil.printStackTrace(e); - } - } - return null; - } - - @SuppressWarnings("unchecked") - public static T invokeGetters(Object object, Method[] getters, Class resultClass) { - try { - for (Method getter : getters) { - object = getter.invoke(object); - } - if (resultClass.isInstance(object)) - return (T)object; - } catch (Exception e) { - assert ExceptionUtil.printStackTrace(e); - } - return null; - } - - @SuppressWarnings("unchecked") - public static T invokeGetter(Object object, String getterName) { - if (object != null) { - try { - return (T) getGetter(object.getClass(), getterName).invoke(object); - } catch (Exception e) { - assert ExceptionUtil.printStackTrace(e); - } - } - return null; - } - - @SuppressWarnings("unchecked") - public static T invokeGetters(Object object, String... getterNames) { - try { - for (String getterName : getterNames) { - object = object.getClass().getMethod(getterName, parameterTypes).invoke(object); - } - return (T)object; - } catch (Exception e) { - assert ExceptionUtil.printStackTrace(e); - return null; - } - } - - public static Method getGetter(Class clazz, String methodName) { - try { - return clazz.getMethod(methodName, parameterTypes); - } catch (Exception e) { - assert ExceptionUtil.printStackTrace(e); - return null; - } - } - - public static boolean equals(Object o1, Object o2) { - return (o1 != null) && o1.equals(o2); - } -} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java index af329436..43562cce 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java @@ -13,6 +13,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileClassDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileTryStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.util.DefaultList; @@ -20,72 +21,144 @@ import java.util.HashMap; import java.util.ListIterator; -import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.*; - public class SwitchStatementMaker { protected static final Integer MINUS_ONE = Integer.valueOf(-1); @SuppressWarnings("unchecked") - public static void makeSwitchString(LocalVariableMaker localVariableMaker, Statements statements, SwitchStatement switchStatement) { + public static void makeSwitchString(LocalVariableMaker localVariableMaker, Statements statements, SwitchStatement switchStatement) { int size = statements.size(); SwitchStatement previousSwitchStatement = (SwitchStatement)statements.get(size - 2); if ((previousSwitchStatement.getCondition().getLineNumber() == switchStatement.getCondition().getLineNumber()) && (previousSwitchStatement.getCondition().getClass() == MethodInvocationExpression.class)) { - AbstractLocalVariable syntheticLV1 = invokeGetters(previousSwitchStatement.getCondition(), getExpression_getLocalVariable, AbstractLocalVariable.class); + Expression expression = previousSwitchStatement.getCondition(); - if (ReflectionUtil.equals(syntheticLV1, invokeGetters(statements.get(size - 4), getExpression_getLeftExpression_getLocalVariable))) { - BinaryOperatorExpression boe2 = invokeGetter(statements.get(size - 3), getExpression, BinaryOperatorExpression.class); + if (expression.getClass() == MethodInvocationExpression.class) { + expression = ((MethodInvocationExpression)expression).getExpression(); - if ((boe2 != null) && MINUS_ONE.equals(invokeGetters(boe2, getRightExpression_getValue))) { - AbstractLocalVariable syntheticLV2 = invokeGetter(switchStatement.getCondition(), getLocalVariable, AbstractLocalVariable.class); + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable syntheticLV1 = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + Statement statement = statements.get(size - 4); - if (ReflectionUtil.equals(syntheticLV2, invokeGetter(boe2.getLeftExpression(), getLocalVariable))) { - MethodInvocationExpression mie = (MethodInvocationExpression) previousSwitchStatement.getCondition(); + if (statement.getClass() == ExpressionStatement.class) { + expression = ((ExpressionStatement)statement).getExpression(); - if (mie.getName().equals("hashCode") && mie.getDescriptor().equals("()I")) { - // Pattern found ==> Parse cases of the synthetic switch statement 'previousSwitchStatement' - HashMap map = new HashMap<>(); + if (expression.getClass() == BinaryOperatorExpression.class) { + expression = ((BinaryOperatorExpression)expression).getLeftExpression(); - // Create map string> - for (SwitchStatement.Block block : previousSwitchStatement.getBlocks()) { - BaseStatement stmts = block.getStatements(); + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable lv2 = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); - assert (stmts != null) && (stmts instanceof Statements) && !((Statements)stmts).isEmpty(); + if (syntheticLV1.equals(lv2)) { + statement = statements.get(size - 3); - for (Statement stmt : (Statements)stmts) { - if (stmt.getClass() != IfStatement.class) { - break; - } + if (statement.getClass() == ExpressionStatement.class) { + expression = ((ExpressionStatement)statement).getExpression(); - IfStatement is = (IfStatement) stmt; - String string = invokeGetters(is.getCondition(), getParameters_getString, String.class); - Statements sal = (Statements) is.getStatements(); - Integer index = invokeGetters(sal.get(0), getExpression_getRightExpression_getValue, Integer.class); - map.put(index, string); - } - } + if (expression.getClass() == BinaryOperatorExpression.class) { + BinaryOperatorExpression boe2 = (BinaryOperatorExpression) expression; - // Replace synthetic index by string - for (SwitchStatement.Block block : switchStatement.getBlocks()) { - SwitchStatement.LabelBlock lb = (SwitchStatement.LabelBlock) block; + expression = boe2.getRightExpression(); - if (lb.getLabel() != SwitchStatement.DEFAULT_LABEL) { - SwitchStatement.ExpressionLabel el = (SwitchStatement.ExpressionLabel) lb.getLabel(); - IntegerConstantExpression nce = (IntegerConstantExpression) el.getExpression(); - el.setExpression(new StringConstantExpression(nce.getLineNumber(), map.get(nce.getValue()))); - } - } + if ((expression.getClass() == IntegerConstantExpression.class) && MINUS_ONE.equals(((IntegerConstantExpression)expression).getValue())) { + expression = switchStatement.getCondition(); + + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable syntheticLV2 = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + + if (syntheticLV2.equals(((ClassFileLocalVariableReferenceExpression)boe2.getLeftExpression()).getLocalVariable())) { + MethodInvocationExpression mie = (MethodInvocationExpression) previousSwitchStatement.getCondition(); + + if (mie.getName().equals("hashCode") && mie.getDescriptor().equals("()I")) { + // Pattern found ==> Parse cases of the synthetic switch statement 'previousSwitchStatement' + HashMap map = new HashMap<>(); + + // Create map string> + for (SwitchStatement.Block block : previousSwitchStatement.getBlocks()) { + BaseStatement stmts = block.getStatements(); + + assert (stmts != null) && (stmts.getClass() == Statements.class) && !((Statements) stmts).isEmpty(); + + for (Statement stmt : (Statements) stmts) { + if (stmt.getClass() != IfStatement.class) { + break; + } + + IfStatement is = (IfStatement) stmt; + + expression = is.getCondition(); + + if (expression.getClass() != MethodInvocationExpression.class) { + break; + } + + expression = ((MethodInvocationExpression) expression).getParameters().getFirst(); + + if (expression.getClass() != StringConstantExpression.class) { + break; + } + + String string = ((StringConstantExpression) expression).getString(); + + statement = is.getStatements().getFirst(); + + if (statement.getClass() != ExpressionStatement.class) { + break; + } + + expression = ((ExpressionStatement) statement).getExpression(); + + if (expression.getClass() != BinaryOperatorExpression.class) { + break; + } + + expression = ((BinaryOperatorExpression) expression).getRightExpression(); + + if (expression.getClass() != IntegerConstantExpression.class) { + break; + } + + Integer index = ((IntegerConstantExpression) expression).getValue(); + map.put(index, string); + } + } - // Replace synthetic key - switchStatement.setCondition(invokeGetters(statements.get(size - 4), getExpression_getRightExpression, Expression.class)); + // Replace synthetic index by string + for (SwitchStatement.Block block : switchStatement.getBlocks()) { + SwitchStatement.LabelBlock lb = (SwitchStatement.LabelBlock) block; - // Remove next synthetic statements - statements.subList(size - 4, size - 1).clear(); + if (lb.getLabel() != SwitchStatement.DEFAULT_LABEL) { + SwitchStatement.ExpressionLabel el = (SwitchStatement.ExpressionLabel) lb.getLabel(); + IntegerConstantExpression nce = (IntegerConstantExpression) el.getExpression(); + el.setExpression(new StringConstantExpression(nce.getLineNumber(), map.get(nce.getValue()))); + } + } - // Remove synthetic local variables - localVariableMaker.removeLocalVariable(syntheticLV1); - localVariableMaker.removeLocalVariable(syntheticLV2); + // Replace synthetic key + statement = statements.get(size - 4); + + if (statement.getClass() == ExpressionStatement.class) { + expression = ((ExpressionStatement) statement).getExpression(); + + if (expression.getClass() == BinaryOperatorExpression.class) { + switchStatement.setCondition(((BinaryOperatorExpression)expression).getRightExpression()); + + // Remove next synthetic statements + statements.subList(size - 4, size - 1).clear(); + + // Remove synthetic local variables + localVariableMaker.removeLocalVariable(syntheticLV1); + localVariableMaker.removeLocalVariable(syntheticLV2); + } + } + } + } + } + } + } + } + } + } } } } @@ -157,8 +230,34 @@ protected static void updateSwitchStatement(SwitchStatement switchStatement, Lis } BinaryOperatorExpression boe = (BinaryOperatorExpression)expression; - Integer index = invokeGetters(boe, getRightExpression_getValue, Integer.class); - String name = invokeGetters(boe, getLeftExpression_getIndex_getExpression_getName, String.class); + + expression = boe.getRightExpression(); + + if (expression.getClass() != IntegerConstantExpression.class) { + break; + } + + Integer index = ((IntegerConstantExpression)expression).getValue(); + + expression = boe.getLeftExpression(); + + if (expression.getClass() != ArrayExpression.class) { + break; + } + + expression = ((ArrayExpression)expression).getIndex(); + + if (expression.getClass() != MethodInvocationExpression.class) { + break; + } + + expression = ((MethodInvocationExpression)expression).getExpression(); + + if (expression.getClass() != FieldReferenceExpression.class) { + break; + } + + String name = ((FieldReferenceExpression)expression).getName(); map.put(index, name); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java index f975054a..d4ad0a0d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java @@ -10,6 +10,7 @@ import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.expression.BinaryOperatorExpression; import org.jd.core.v1.model.javasyntax.expression.Expression; +import org.jd.core.v1.model.javasyntax.statement.ExpressionStatement; import org.jd.core.v1.model.javasyntax.statement.Statement; import org.jd.core.v1.model.javasyntax.statement.Statements; import org.jd.core.v1.model.javasyntax.statement.SynchronizedStatement; @@ -20,13 +21,10 @@ import java.util.Iterator; -import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.getExpression; -import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.invokeGetter; - public class SynchronizedStatementMaker { - public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements) { + public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements) { // Remove monitor enter ClassFileMonitorEnterStatement monitorEnterStatement = (ClassFileMonitorEnterStatement) statements.removeLast(); Expression monitor = monitorEnterStatement.getMonitor(); @@ -35,16 +33,24 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements s if (monitorClass == ClassFileLocalVariableReferenceExpression.class) { if (!statements.isEmpty()) { - BinaryOperatorExpression boe = invokeGetter(statements.removeLast(), getExpression, BinaryOperatorExpression.class); - - if ((boe != null) && (boe.getLeftExpression().getClass() == ClassFileLocalVariableReferenceExpression.class)) { - ClassFileLocalVariableReferenceExpression m = (ClassFileLocalVariableReferenceExpression) monitor; - ClassFileLocalVariableReferenceExpression l = boe.getGenericLeftExpression(); - assert l.getLocalVariable() == m.getLocalVariable(); - // Update monitor - monitor = boe.getRightExpression(); - // Store synthetic local variable - localVariable = l.getLocalVariable(); + Statement statement = statements.removeLast(); + + if (statement.getClass() == ExpressionStatement.class) { + Expression expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() == BinaryOperatorExpression.class) { + BinaryOperatorExpression boe = (BinaryOperatorExpression)expression; + + if ((boe != null) && (boe.getLeftExpression().getClass() == ClassFileLocalVariableReferenceExpression.class)) { + ClassFileLocalVariableReferenceExpression m = (ClassFileLocalVariableReferenceExpression) monitor; + ClassFileLocalVariableReferenceExpression l = boe.getGenericLeftExpression(); + assert l.getLocalVariable() == m.getLocalVariable(); + // Update monitor + monitor = boe.getRightExpression(); + // Store synthetic local variable + localVariable = l.getLocalVariable(); + } + } } } } else if (monitorClass == BinaryOperatorExpression.class) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java index 33c2940b..66d25d3a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java @@ -20,12 +20,10 @@ import java.util.List; -import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.*; - public class TryWithResourcesStatementMaker { - public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, DefaultList catchClauses, Statements finallyStatements) { + public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, DefaultList catchClauses, Statements finallyStatements) { int size = statements.size(); if ((size < 2) || (finallyStatements == null) || (finallyStatements.size() != 1) || !checkThrowable(catchClauses)) { @@ -38,38 +36,132 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements s return null; } - BinaryOperatorExpression boe = invokeGetter(statements.get(size-2), getExpression, BinaryOperatorExpression.class); + IfStatement is = (IfStatement)statement; + + statement = statements.get(size-2); - if (boe == null) { + if (statement.getClass() != ExpressionStatement.class) { return null; } - IfStatement is = (IfStatement)statement; - AbstractLocalVariable lv1 = invokeGetter(boe.getLeftExpression(), getLocalVariable, AbstractLocalVariable.class); - AbstractLocalVariable lv2 = invokeGetters(statements.get(size-1), getExpression_getLeftExpression_getLocalVariable, AbstractLocalVariable.class); - IfElseStatement ies = invokeGetters(is, getStatements_getFirst, IfElseStatement.class); + Expression expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() != BinaryOperatorExpression.class) { + return null; + } + + BinaryOperatorExpression boe = (BinaryOperatorExpression)expression; + + expression = boe.getLeftExpression(); + + if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { + return null; + } + + AbstractLocalVariable lv1 = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + + statement = statements.get(size-1); + + if (statement.getClass() != ExpressionStatement.class) { + return null; + } + + expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() != BinaryOperatorExpression.class) { + return null; + } + + expression = ((BinaryOperatorExpression)expression).getLeftExpression(); + + if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { + return null; + } + + AbstractLocalVariable lv2 = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + + statement = is.getStatements().getFirst(); + + if (statement.getClass() != IfElseStatement.class) { + return null; + } + + IfElseStatement ies = (IfElseStatement)statement; + + if (lv1 != getLocalVariable(is.getCondition())) { + return null; + } + + statement = ies.getStatements().getFirst(); - if ((lv1 == null) || (lv2 == null) || (ies == null) || (lv1 != getLocalVariable(is.getCondition()))) { + if (statement.getClass() != ClassFileTryStatement.class) { return null; } - TryStatement ts = invokeGetters(ies, getStatements_getFirst, TryStatement.class); - MethodInvocationExpression mie = invokeGetters(ies, getElseStatements_getFirst_getExpression, MethodInvocationExpression.class); + ClassFileTryStatement ts = (ClassFileTryStatement)statement; - if ((ts == null) || (mie == null) || (is.getCondition().getLineNumber() != mie.getLineNumber()) || (ts.getFinallyStatements() != null) || + statement = ies.getElseStatements().getFirst(); + + if (statement.getClass() != ExpressionStatement.class) { + return null; + } + + expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() != MethodInvocationExpression.class) { + return null; + } + + MethodInvocationExpression mie = (MethodInvocationExpression)expression; + + if ((is.getCondition().getLineNumber() != mie.getLineNumber()) || (ts.getFinallyStatements() != null) || (lv2 != getLocalVariable(ies.getCondition())) || !checkThrowable(ts.getCatchClauses()) || !checkCloseInvocation(mie, lv1)) { return null; } - mie = invokeGetters(ts.getTryStatements(), getFirst_getExpression, MethodInvocationExpression.class); + statement = ts.getTryStatements().getFirst(); - if ((mie == null) || !checkCloseInvocation(mie, lv1)) { + if (statement.getClass() != ExpressionStatement.class) { return null; } - mie = invokeGetters(ts.getCatchClauses().get(0).getStatements(), getFirst_getExpression, MethodInvocationExpression.class); + expression = ((ExpressionStatement)statement).getExpression(); - if (!mie.getName().equals("addSuppressed") || !mie.getDescriptor().equals("(Ljava/lang/Throwable;)V") || (invokeGetters(mie, getExpression_getLocalVariable) != lv2)) { + if (expression.getClass() != MethodInvocationExpression.class) { + return null; + } + + mie = (MethodInvocationExpression)expression; + + if (!checkCloseInvocation(mie, lv1)) { + return null; + } + + statement = ts.getCatchClauses().get(0).getStatements().getFirst(); + + if (statement.getClass() != ExpressionStatement.class) { + return null; + } + + expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() != MethodInvocationExpression.class) { + return null; + } + + mie = (MethodInvocationExpression)expression; + + if (!mie.getName().equals("addSuppressed") || !mie.getDescriptor().equals("(Ljava/lang/Throwable;)V")) { + return null; + } + + expression = mie.getExpression(); + + if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { + return null; + } + + if (((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable() != lv2) { return null; } @@ -106,6 +198,14 @@ protected static AbstractLocalVariable getLocalVariable(Expression condition) { } protected static boolean checkCloseInvocation(MethodInvocationExpression mie, AbstractLocalVariable lv) { - return mie.getName().equals("close") && mie.getDescriptor().equals("()V") && (invokeGetters(mie, getExpression_getLocalVariable) == lv); + if (mie.getName().equals("close") && mie.getDescriptor().equals("()V")) { + Expression expression = mie.getExpression(); + + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + return ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable() == lv; + } + } + + return false; } } diff --git a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java index af90ee54..84963cc2 100644 --- a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java +++ b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java @@ -13,7 +13,7 @@ import org.jd.core.v1.loader.ZipLoader; import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.model.javasyntax.CompilationUnit; -import org.jd.core.v1.model.javasyntax.declaration.BaseTypeDeclaration; +import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.message.Message; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; @@ -33,7 +33,7 @@ import java.util.List; import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; -import static org.jd.core.v1.service.converter.classfiletojavasyntax.util.ReflectionUtil.invokeGetter; + public class ControlFlowGraphTest extends TestCase { protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); @@ -2663,27 +2663,39 @@ protected Method searchMethod(Loader loader, ObjectTypeMaker factory, SignatureP assertNotNull(compilationUnit); BaseTypeDeclaration typeDeclarations = compilationUnit.getTypeDeclarations(); - ClassFileBodyDeclaration bodyDeclaration = invokeGetter(typeDeclarations, "getBodyDeclaration"); - - for (ClassFileMemberDeclaration md : bodyDeclaration.getMethodDeclarations()) { - if (md instanceof ClassFileMethodDeclaration) { - ClassFileMethodDeclaration cfmd = (ClassFileMethodDeclaration) md; - if (cfmd.getName().equals(methodName)) { - if ((methodDescriptor == null) || cfmd.getDescriptor().equals(methodDescriptor)) { - return cfmd.getMethod(); + BodyDeclaration bodyDeclaration = null; + + if (typeDeclarations instanceof EnumDeclaration) { + bodyDeclaration = ((EnumDeclaration)typeDeclarations).getBodyDeclaration(); + } else if (typeDeclarations instanceof AnnotationDeclaration) { + bodyDeclaration = ((AnnotationDeclaration)typeDeclarations).getBodyDeclaration(); + } else if (typeDeclarations instanceof InterfaceDeclaration) { + bodyDeclaration = ((InterfaceDeclaration)typeDeclarations).getBodyDeclaration(); + } + + if (bodyDeclaration != null) { + ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) bodyDeclaration; + + for (ClassFileMemberDeclaration md : cfbd.getMethodDeclarations()) { + if (md instanceof ClassFileMethodDeclaration) { + ClassFileMethodDeclaration cfmd = (ClassFileMethodDeclaration) md; + if (cfmd.getName().equals(methodName)) { + if ((methodDescriptor == null) || cfmd.getDescriptor().equals(methodDescriptor)) { + return cfmd.getMethod(); + } } - } - } else if (md instanceof ClassFileConstructorDeclaration) { - ClassFileConstructorDeclaration cfcd = (ClassFileConstructorDeclaration)md; - if (cfcd.getMethod().getName().equals(methodName)) { - if ((methodDescriptor == null) || cfcd.getDescriptor().equals(methodDescriptor)) { - return cfcd.getMethod(); + } else if (md instanceof ClassFileConstructorDeclaration) { + ClassFileConstructorDeclaration cfcd = (ClassFileConstructorDeclaration) md; + if (cfcd.getMethod().getName().equals(methodName)) { + if ((methodDescriptor == null) || cfcd.getDescriptor().equals(methodDescriptor)) { + return cfcd.getMethod(); + } + } + } else if (md instanceof ClassFileStaticInitializerDeclaration) { + ClassFileStaticInitializerDeclaration cfsid = (ClassFileStaticInitializerDeclaration) md; + if (cfsid.getMethod().getName().equals(methodName)) { + return cfsid.getMethod(); } - } - } else if (md instanceof ClassFileStaticInitializerDeclaration) { - ClassFileStaticInitializerDeclaration cfsid = (ClassFileStaticInitializerDeclaration)md; - if (cfsid.getMethod().getName().equals(methodName)) { - return cfsid.getMethod(); } } } From b3ccba8366b4fa771207d5cb8be71722676f4f1a Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 21 Jun 2019 07:47:57 +0200 Subject: [PATCH 029/211] Update version to 1.0.5 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 87916b9d..11db6dba 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.0.4' +version='1.0.5' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From 6019a909f85eeb8a23b53980db8e610ee9957c0f Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 22 Jun 2019 12:34:41 +0200 Subject: [PATCH 030/211] Improve loop reconstruction --- .../util/ControlFlowGraphReducer.java | 53 +- .../util/LoopStatementMaker.java | 17 +- .../SearchLocalVariableReferenceVisitor.java | 33 + .../resources/java/org/jd/core/test/For.java | 706 +++++++++--------- .../zip/data-java-jdk-1.7.0-no-debug-info.zip | Bin 4330 -> 4825 bytes .../resources/zip/data-java-jdk-1.7.0.zip | Bin 63824 -> 64074 bytes .../resources/zip/data-java-jdk-1.8.0.zip | Bin 67076 -> 67320 bytes .../resources/zip/data-java-jdk-10.0.2.zip | Bin 14743 -> 18745 bytes .../resources/zip/data-java-jdk-9.0.1.zip | Bin 14729 -> 18731 bytes 9 files changed, 436 insertions(+), 373 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableReferenceVisitor.java diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index b9d2344e..4639805c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -8,6 +8,7 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; import org.jd.core.v1.model.classfile.attribute.AttributeCode; +import org.jd.core.v1.model.javasyntax.expression.Expression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; @@ -1260,31 +1261,41 @@ protected static void createContinueLoop(BitSet visited, BasicBlock basicBlock) protected static void createContinueLoop(BitSet visited, BasicBlock basicBlock, BasicBlock subBasicBlock) { if (subBasicBlock != null) { - if ((subBasicBlock.getPredecessors().size() > 1) && (basicBlock.getFromOffset() < subBasicBlock.getFromOffset()) && (basicBlock.getFirstLineNumber() > subBasicBlock.getFirstLineNumber())) { - Set predecessors = subBasicBlock.getPredecessors(); - Iterator iterator = predecessors.iterator(); - BasicBlock lastPredecessor = iterator.next(); - - if (lastPredecessor.getType() != TYPE_GOTO_IN_TERNARY_OPERATOR) { - while (iterator.hasNext()) { - BasicBlock predecessor = iterator.next(); - if (predecessor.getType() == TYPE_GOTO_IN_TERNARY_OPERATOR) { - lastPredecessor = null; - break; - } - if (lastPredecessor.getFromOffset() < predecessor.getFromOffset()) { - lastPredecessor = predecessor; - } - } + if ((subBasicBlock.getPredecessors().size() > 1) && (basicBlock.getFromOffset() < subBasicBlock.getFromOffset())) { + boolean condition; + + if (basicBlock.getFirstLineNumber() == Expression.UNKNOWN_LINE_NUMBER) { + condition = subBasicBlock.matchType(GROUP_SINGLE_SUCCESSOR) && (subBasicBlock.getNext().getType() == TYPE_LOOP_START); + } else { + condition = (basicBlock.getFirstLineNumber() > subBasicBlock.getFirstLineNumber()); + } - if (lastPredecessor != null) { - iterator = predecessors.iterator(); + if (condition) { + Set predecessors = subBasicBlock.getPredecessors(); + Iterator iterator = predecessors.iterator(); + BasicBlock lastPredecessor = iterator.next(); + if (lastPredecessor.getType() != TYPE_GOTO_IN_TERNARY_OPERATOR) { while (iterator.hasNext()) { BasicBlock predecessor = iterator.next(); - if (predecessor != lastPredecessor) { - iterator.remove(); - predecessor.replace(subBasicBlock, LOOP_CONTINUE); + if (predecessor.getType() == TYPE_GOTO_IN_TERNARY_OPERATOR) { + lastPredecessor = null; + break; + } + if (lastPredecessor.getFromOffset() < predecessor.getFromOffset()) { + lastPredecessor = predecessor; + } + } + + if (lastPredecessor != null) { + iterator = predecessors.iterator(); + + while (iterator.hasNext()) { + BasicBlock predecessor = iterator.next(); + if (predecessor != lastPredecessor) { + iterator.remove(); + predecessor.replace(subBasicBlock, LOOP_CONTINUE); + } } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index 827f2673..e23e207a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -17,6 +17,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchLocalVariableReferenceVisitor; import java.util.Collections; import java.util.Iterator; @@ -567,7 +568,7 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker boe = (BinaryOperatorExpression)es.getExpression(); - if ((boe == null) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { + if (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) { return null; } @@ -589,15 +590,23 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker return null; } + // Check if 'i$' is not used in sub-statements + SearchLocalVariableReferenceVisitor visitor = new SearchLocalVariableReferenceVisitor(syntheticIterator); + + for (int i=1, len=subStatements.size(); i list) { - System.out.println("start"); + public void testForEach(List list) { + System.out.println("start"); - for (String s : list) - System.out.println(s); + for (String s : list) + System.out.println(s); - System.out.println("end"); - } + System.out.println("end"); + } - public void forTry(int i, Object o) { - System.out.println("start"); + public void forTry(int i, Object o) { + System.out.println("start"); - for (i=0; i<10; i++) { - System.out.println("a"); - try { - System.out.println("b"); - } catch (RuntimeException e) { - System.out.println("c"); - } - } + for (i=0; i<10; i++) { + System.out.println("a"); + try { + System.out.println("b"); + } catch (RuntimeException e) { + System.out.println("c"); + } + } - System.out.println("end"); - } + System.out.println("end"); + } public void forTryReturn(int i, Object o) { System.out.println("start"); @@ -298,186 +299,195 @@ public void forTryReturn(int i, Object o) { } public Object forFor() { - System.out.println("start"); + System.out.println("start"); + + for (int i=0; i<5; ++i) + { + if (this == null) return null; + System.out.println(i); + } + + for (int i : new int[] { 4 }) + { + if (0 == i) + { + System.out.println(i); + } + } + + System.out.println("end"); + + return this; + } + + public void forIf() { + System.out.println("start"); + + for (int i=0; i<10; i++) + { + System.out.println("b"); + if (i == 4) + System.out.println("c"); + System.out.println("d"); + } + + if (this == null) + System.out.println("e"); + + System.out.println("end"); + } + + private static void forAndEmptyDoWhile() { + System.out.println("start"); + + int i; + + for (i=0; i<20; i++) + System.out.println(i); + + do; + while (i < 10); + + System.out.println("end"); + } + + private static void forAndEmptyDoWhileTestOr() { + System.out.println("start"); + + int i; + + for (i=0; i<10; i++) + System.out.println(i); + + do; + while ((i < 20) || (i < 10) || (i < 0)); + + System.out.println("end"); + } - for (int i=0; i<5; ++i) - { - if (this == null) return null; - System.out.println(i); - } + private static void forAndEmptyDoWhileTestAnd() { + System.out.println("start"); - for (int i : new int[] { 4 }) - { - if (0 == i) - { - System.out.println(i); - } - } + int i; - System.out.println("end"); + for (i=0; i<10; i++) + System.out.println(i); - return this; - } + do; + while ((i < 20) && (i < 10) && (i < 0)); - public void forIf() { - System.out.println("start"); + System.out.println("end"); + } - for (int i=0; i<10; i++) - { - System.out.println("b"); - if (i == 4) - System.out.println("c"); - System.out.println("d"); - } + public static void forEachArray(String[] array) { + System.out.println("start"); - if (this == null) - System.out.println("e"); + for(String s : array) { + System.out.println(s); + } - System.out.println("end"); - } + for(String s : array) { + System.out.println(s); + } - private static void forAndEmptyDoWhile() { - System.out.println("start"); + System.out.println("end"); + } - int i; + public static void forEachList(List list) { + System.out.println("start"); - for (i=0; i<20; i++) - System.out.println(i); + for(String s : list) { + System.out.println(s); + } - do; - while (i < 10); + for(String s : list) { + System.out.println(s); + } - System.out.println("end"); - } + System.out.println("end"); + } - private static void forAndEmptyDoWhileTestOr() { - System.out.println("start"); + public void notAForEach() { + Iterator iterator = Arrays.asList(this.getClass().getInterfaces()).iterator(); + while (iterator.hasNext()) { + Class clazz = iterator.next(); + System.out.println(clazz); + } - int i; + System.out.println(iterator); + } - for (i=0; i<10; i++) - System.out.println(i); + public static void forUnderscore(String[] __) { + for (int ___ = 0; ___ < __.length; ___++) + System.out.println(__[___]); + } - do; - while ((i < 20) || (i < 10) || (i < 0)); + private byte[] forTryReturn() throws Exception + { + for(int i=0; i<3; i++) { + try { + byte[] data = null; + return data; + } catch (Exception e) { + Thread.sleep(300); + } + } + throw new Exception("comm error"); + } - System.out.println("end"); - } + protected boolean ifForIfReturn(int[] array) { + boolean flag = false; - private static void forAndEmptyDoWhileTestAnd() { - System.out.println("start"); + if (flag == false) { + for (int i : array) { + if (flag != false) + break; + } - int i; + if (flag == false) { + flag = true; + } + } + + return flag; + } + + public static void forIfContinue() { + System.out.println("start"); - for (i=0; i<10; i++) - System.out.println(i); + for (int i=0; i<100; i++) { + System.out.println("a"); + if (i == 0) { + System.out.println("b"); + if (i == 1) { + continue; + } + System.out.println("c"); + } + System.out.println("d"); + } - do; - while ((i < 20) && (i < 10) && (i < 0)); - - System.out.println("end"); - } - - public static void forEachArray(String[] array) { - System.out.println("start"); - - for(String s : array) { - System.out.println(s); - } - - for(String s : array) { - System.out.println(s); - } - - System.out.println("end"); - } - - public static void forEachList(List list) { - System.out.println("start"); - - for(String s : list) { - System.out.println(s); - } - - for(String s : list) { - System.out.println(s); - } - - System.out.println("end"); - } - - public void notAForEach() { - Iterator iterator = Arrays.asList(this.getClass().getInterfaces()).iterator(); - while (iterator.hasNext()) { - Class clazz = iterator.next(); - System.out.println(clazz); - } - - System.out.println(iterator); - } - - public static void forUnderscore(String[] __) { - for (int ___ = 0; ___ < __.length; ___++) - System.out.println(__[___]); - } - - private byte[] forTryReturn() throws Exception - { - for(int i=0; i<3; i++) { - try { - byte[] data = null; - return data; - } catch (Exception e) { - Thread.sleep(300); - } - } - throw new Exception("comm error"); - } - - protected boolean ifForIfReturn(int[] array) { - boolean flag = false; - - if (flag == false) { - for (int i : array) { - if (flag != false) - break; - } - - if (flag == false) { - flag = true; - } - } - - return flag; - } - - public static void forIfContinue() { - System.out.println("start"); - - for (int i=0; i<100; i++) { - System.out.println("a"); - if (i == 0) { - System.out.println("b"); - if (i == 1) { - continue; - } - System.out.println("c"); - } - System.out.println("d"); - } - - System.out.println("end"); - } - - public void forIfIfContinue() { - for (int i=0; i<100; i++) { - if (i == 1) { - // Empty line - if (i != 2) { - continue; - } - } - i += 42; - } - } + System.out.println("end"); + } + + public void forIfIfContinue() { + for (int i=0; i<100; i++) { + if (i == 1) { + // Empty line + if (i != 2) { + continue; + } + } + i += 42; + } + } + + public void forIterator(Map map) { + for (Iterator it = map.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + if (entry.getValue() instanceof String) { + it.remove(); + } + } + } } diff --git a/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip b/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip index 03b520b7d1530fd3770cd71c695a602bcdbe7613..f7b963517e248f0b429f6085da2804cb082c121c 100644 GIT binary patch delta 2475 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 delta 1950 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 bHj}X%6O&RoHx3T~4*+}y005^#00000nU|Ll delta 50 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 XHj^ Date: Sat, 22 Jun 2019 12:35:17 +0200 Subject: [PATCH 031/211] Improve local variable reconstruction --- .../model/localvariable/Frame.java | 14 +- .../model/localvariable/LocalVariableSet.java | 50 ++--- .../util/LocalVariableMaker.java | 6 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 200 +++++++++--------- 4 files changed, 136 insertions(+), 134 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index aab0f771..a86eefe4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -40,7 +40,7 @@ public Frame(Frame parent, Statements statements) { } public void addLocalVariable(AbstractLocalVariable lv) { - assert lv.next == null; + assert lv.getNext() == null; int index = lv.getIndex(); @@ -54,7 +54,7 @@ public void addLocalVariable(AbstractLocalVariable lv) { if (next != lv) { localVariableArray[index] = lv; - lv.next = next; + lv.setNext(next); lv.setFrame(this); } } @@ -177,8 +177,8 @@ public void createNames(HashSet parentNames) { } else { names.add(lv.name); } - assert lv != lv.next; - lv = lv.next; + assert lv != lv.getNext(); + lv = lv.getNext(); } } @@ -203,7 +203,7 @@ public void createNames(HashSet parentNames) { lv.getType().accept(visitor); lv.name = visitor.getName(); } - lv = lv.next; + lv = lv.getNext(); } } @@ -338,7 +338,7 @@ protected HashMap> createMapForInlineDecla variablesToDeclare.add(lv); } } - lv = lv.next; + lv = lv.getNext(); } } @@ -567,7 +567,7 @@ protected void createStartBlockDeclarations() { lv.setDeclared(true); } - lv = lv.next; + lv = lv.getNext(); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java index 55175042..344aeffc 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java @@ -29,23 +29,23 @@ public void add(int index, AbstractLocalVariable newLV) { array[index] = newLV; } else if (lv.fromOffset < newLV.fromOffset) { assert newLV != lv; - newLV.next = lv; + newLV.setNext(lv); array[index] = newLV; } else { AbstractLocalVariable previous = lv; - lv = lv.next; + lv = lv.getNext(); while ((lv != null) && (lv.fromOffset > newLV.fromOffset)) { previous = lv; - lv = lv.next; + lv = lv.getNext(); } assert previous != newLV; - previous.next = newLV; + previous.setNext(newLV); assert newLV != lv; - newLV.next = lv; + newLV.setNext(lv); } } @@ -57,9 +57,9 @@ public AbstractLocalVariable root(int index) { AbstractLocalVariable lv = array[index]; if (lv != null) { - while (lv.next != null) { - assert lv != lv.next; - lv = lv.next; + while (lv.getNext() != null) { + assert lv != lv.getNext(); + lv = lv.getNext(); } return lv; } @@ -76,19 +76,19 @@ public AbstractLocalVariable remove(int index, int offset) { while (lv != null) { if (lv.fromOffset <= offset) { if (previous == null) { - array[index] = lv.next; + array[index] = lv.getNext(); } else { - previous.next = lv.next; + previous.setNext(lv.getNext()); } size--; - lv.next = null; + lv.setNext(null); return lv; } previous = lv; - assert lv != lv.next; - lv = lv.next; + assert lv != lv.getNext(); + lv = lv.getNext(); } } @@ -110,8 +110,8 @@ public void update(int index, int offset, ObjectType type) { break; } - assert lv != lv.next; - lv = lv.next; + assert lv != lv.getNext(); + lv = lv.getNext(); } } } @@ -124,21 +124,21 @@ public void update(int index, int offset, GenericType type) { while (lv != null) { if (lv.fromOffset == offset) { GenericLocalVariable glv = new GenericLocalVariable(index, lv.fromOffset, type, lv.name); - glv.next = lv.next; + glv.setNext(lv.getNext()); if (previous == null) { array[index] = glv; } else { assert previous != glv; - previous.next = glv; + previous.setNext(glv); } break; } previous = lv; - assert lv != lv.next; - lv = lv.next; + assert lv != lv.getNext(); + lv = lv.getNext(); } } } @@ -152,21 +152,21 @@ public AbstractLocalVariable[] initialize(Frame rootFrame) { if (lv != null) { AbstractLocalVariable previous = null; - while (lv.next != null) { + while (lv.getNext() != null) { previous = lv; - assert lv != lv.next; - lv = lv.next; + assert lv != lv.getNext(); + lv = lv.getNext(); } if (lv.fromOffset == 0) { if (previous == null) { - array[index] = lv.next; + array[index] = lv.getNext(); } else { - previous.next = lv.next; + previous.setNext(lv.getNext()); } size--; - lv.next = null; + lv.setNext(null); rootFrame.addLocalVariable(lv); cache[index] = lv; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index d973a40d..8aa13e1a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -313,8 +313,10 @@ public AbstractLocalVariable getLocalVariable(int index, int offset) { } else if (lv.getFrame() != currentFrame) { Frame frame = searchCommonParentFrame(lv.getFrame(), currentFrame); frame.mergeLocalVariable(lv); - lv.setNext(null); - frame.addLocalVariable(lv); + if (lv.getFrame() != frame) { + lv.getFrame().removeLocalVariable(lv); + frame.addLocalVariable(lv); + } } lv.setToOffset(offset); diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 7ef381d7..89e6e0a0 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -114,7 +114,7 @@ public void testJdk170Basic() throws Exception { assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -160,7 +160,7 @@ public void testJdk170NoDebugBasic() throws Exception { assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -197,7 +197,7 @@ public void testJdk170Constructors() throws Exception { assertTrue(source.matches(PatternMaker.make(": 39]", "this.short123 = 3;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -256,7 +256,7 @@ public void testJdk170IfElse() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 184: 184]", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -285,7 +285,7 @@ public void testJdk170Interface() throws Exception { assertTrue(source.matches(PatternMaker.make("public interface Interface", "extends Serializable"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -330,7 +330,7 @@ public void testJdk170While() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -375,7 +375,7 @@ public void testJdk901While() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -420,7 +420,7 @@ public void testJdk1002While() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -460,7 +460,7 @@ public void testJdk170DoWhile() throws Exception { assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -500,7 +500,7 @@ public void testJdk901DoWhile() throws Exception { assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -540,7 +540,7 @@ public void testJdk1002DoWhile() throws Exception { assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -599,7 +599,7 @@ public void testJdk170BreakContinue() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 162: 0]", "break label16;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -628,56 +628,56 @@ public void testJdk170For() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 16]", "for (int i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 38]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 40]", "for (; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 50]", "for (; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 60]", "for (int i = 0;; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 68]", "for (;; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 76]", "for (int i = 0; i < 10;)"))); - assertTrue(source.matches(PatternMaker.make(": 84]", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 92]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make("[ 100: 0]", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 108]", "for (int i = 0, j = i, size = 10; i < size; j += ++i)"))); - assertTrue(source.matches(PatternMaker.make(": 118]", "int i = 0, j = i, size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 119]", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 120]", "j += ++i)"))); - assertTrue(source.matches(PatternMaker.make(": 130]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 131]", "int j = i;"))); - assertTrue(source.matches(PatternMaker.make(": 132]", "int size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 133]", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 134]", "i++,"))); - assertTrue(source.matches(PatternMaker.make(": 135]", "j += i)"))); - assertTrue(source.matches(PatternMaker.make(": 145]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 147]", "int j = i;"))); - assertTrue(source.matches(PatternMaker.make(": 149]", "int size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 151]", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 153]", "i++,"))); - assertTrue(source.matches(PatternMaker.make(": 155]", "j += i)"))); - assertTrue(source.matches(PatternMaker.make(": 165]", "for (int i = 0; i < 10; i++);"))); - assertTrue(source.matches(PatternMaker.make(": 173]", "for (; i < 10; i++);"))); - assertTrue(source.matches(PatternMaker.make(": 181]", "for (int i = 0;; i++);"))); - assertTrue(source.matches(PatternMaker.make("[ 186: 0]", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 187]", "i++;"))); - assertTrue(source.matches(PatternMaker.make(": 193]", "for (int i = 0; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 199]", "for (int[] i = { 0 }; i.length < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 205]", "for (int i = 0, j = i, k = i; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 211]", "for (int[] i = { 0 }, j = i, k = j; i.length < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 217]", "for (int i = 0, j[] = { 1 }; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 223]", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 229]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make("[ 230: 0]", "while (true);"))); - assertTrue(source.matches(PatternMaker.make(": 241]", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); - assertTrue(source.matches(PatternMaker.make("[ 249: 0]", "while (true) {"))); - assertTrue(source.matches(PatternMaker.make(": 260]", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make(": 385]", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 399]", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); - - assertTrue(source.indexOf("[ 448: 448]") != -1); + assertTrue(source.matches(PatternMaker.make(": 20]", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 42]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 44]", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 54]", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 64]", "for (int i = 0;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 72]", "for (;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 80]", "for (int i = 0; i < 10;)"))); + assertTrue(source.matches(PatternMaker.make(": 88]", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 96]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("[ 104: 0]", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 112]", "for (int i = 0, j = i, size = 10; i < size; j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 122]", "int i = 0, j = i, size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 123]", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 124]", "j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 134]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 135]", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 136]", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 137]", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 138]", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 139]", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 149]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 151]", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 153]", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 155]", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 157]", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 159]", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 169]", "for (int i = 0; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 177]", "for (; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 185]", "for (int i = 0;; i++);"))); + assertTrue(source.matches(PatternMaker.make("[ 190: 0]", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 191]", "i++;"))); + assertTrue(source.matches(PatternMaker.make(": 197]", "for (int i = 0; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 203]", "for (int[] i = { 0 }; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 209]", "for (int i = 0, j = i, k = i; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 215]", "for (int[] i = { 0 }, j = i, k = j; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 221]", "for (int i = 0, j[] = { 1 }; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 227]", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 233]", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("[ 234: 0]", "while (true);"))); + assertTrue(source.matches(PatternMaker.make(": 245]", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); + assertTrue(source.matches(PatternMaker.make("[ 253: 0]", "while (true) {"))); + assertTrue(source.matches(PatternMaker.make(": 264]", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 310]", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make(": 389]", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 403]", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 411]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + + assertTrue(source.indexOf("[ 489: 489]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -714,7 +714,7 @@ public void testJdk170NoDebugFor() throws Exception { assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -755,7 +755,7 @@ public void testJdk150For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 423]", "for (byte b = 0; b < 3; b++)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -796,7 +796,7 @@ public void testJdk160For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -836,7 +836,7 @@ public void testIbmJ9For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -882,7 +882,7 @@ public void testJdk170Array() throws Exception { assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][]", "{ { 1 } ,"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -924,7 +924,7 @@ public void testJdk150Array() throws Exception { assertTrue(source.matches(PatternMaker.make(": 75]", "testInt3(new int[][][] { { { 0, 1"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -962,7 +962,7 @@ public void testJdk170Assert() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1000,7 +1000,7 @@ public void testJdk150Assert() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1045,7 +1045,7 @@ public void testJdk150AnonymousClass() throws Exception { assertTrue(source.matches(PatternMaker.make(": 104]", "System.out.println(\"end\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1108,7 +1108,7 @@ public void testJdk170Switch() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 288: 0]", "default:"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1149,7 +1149,7 @@ public void testJdk170AdvancedSwitch() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 40: 40]", "System.out.println(1);"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1180,7 +1180,7 @@ public void testEclipseJavaCompiler321Switch() throws Exception { assertTrue(source.indexOf("[ 239: 239]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1211,7 +1211,7 @@ public void testEclipseJavaCompiler3130Switch() throws Exception { assertTrue(source.indexOf("[ 239: 239]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1254,7 +1254,7 @@ public void testJdk118TernaryOperator() throws Exception { assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1294,7 +1294,7 @@ public void testJdk170TernaryOperator() throws Exception { assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1345,7 +1345,7 @@ public void testJdk170TryWithResources() throws Exception { assertTrue(source.indexOf("[ 162: 162]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1396,7 +1396,7 @@ public void testJdk180TryWithResources() throws Exception { assertTrue(source.indexOf("[ 162: 162]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1443,7 +1443,7 @@ public void testJdk170Synchronised() throws Exception { assertTrue(source.matches(PatternMaker.make(": 97]", "return subContentEquals(s);"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1487,7 +1487,7 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1545,7 +1545,7 @@ public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1602,7 +1602,7 @@ public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1659,7 +1659,7 @@ public void testJdk118TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1712,7 +1712,7 @@ public void testJdk131TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1772,7 +1772,7 @@ public void testJdk170TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1814,7 +1814,7 @@ public void testJdk170AnnotatedClass() throws Exception { assertTrue(source.indexOf("public void ping(@Deprecated Writer writer, @Deprecated @Value(str = \"localhost\") String host, long timeout)") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1867,7 +1867,7 @@ public void testJdk170AnonymousClass() throws Exception { assertTrue(source.indexOf("} ;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1914,7 +1914,7 @@ public void testJdk170GenericClass() throws Exception { assertTrue(source.indexOf("[ 104: 104]") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1946,7 +1946,7 @@ public void testJdk170AnnotationAuthor() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "Name[] contributors() default {};"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -1982,7 +1982,7 @@ public void testJdk170AnnotationValue() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 27: 0]", "Class clazz() default Object.class;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2065,7 +2065,7 @@ public void testJdk170OuterClass() throws Exception { assertTrue(source.matches(PatternMaker.make("public class InnerInnerClass", "{", "}"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2111,7 +2111,7 @@ public void testJdk170Enum() throws Exception { assertTrue(source.indexOf("public static final enum") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2157,7 +2157,7 @@ public void testJdk901Enum() throws Exception { assertTrue(source.indexOf("public static final enum") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2203,7 +2203,7 @@ public void testJdk1002Enum() throws Exception { assertTrue(source.indexOf("public static final enum") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2240,7 +2240,7 @@ public void testJdk118Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2279,7 +2279,7 @@ public void testJdk142Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2318,7 +2318,7 @@ public void testJdk901Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2357,7 +2357,7 @@ public void testJdk1002Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2402,7 +2402,7 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 67]", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } @@ -2441,7 +2441,7 @@ public void testJdk901InterfaceWithDefaultMethods() throws Exception { assertTrue(source.matches(PatternMaker.make(": 40]", "private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId) { return ZonedDateTime.of(localDateTime, zoneId); }"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1); + assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); assertTrue(source.indexOf("/* ") == -1); } From 42fa3df0c06a8119d5f3688490e7a47248fdc92e Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 29 Jun 2019 18:46:12 +0200 Subject: [PATCH 032/211] Improve 'for' statement reconstruction --- .../util/ControlFlowGraphReducer.java | 119 +++++++++++------- .../util/LoopStatementMaker.java | 13 +- .../util/StatementMaker.java | 31 +++-- .../org/jd/core/v1/ControlFlowGraphTest.java | 5 + .../resources/java/org/jd/core/test/For.java | 21 ++++ .../zip/data-java-jdk-1.7.0-no-debug-info.zip | Bin 4825 -> 5031 bytes .../resources/zip/data-java-jdk-1.7.0.zip | Bin 64074 -> 64357 bytes 7 files changed, 131 insertions(+), 58 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 4639805c..7b553429 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -1031,14 +1031,26 @@ protected static boolean reduceJsr(BitSet visited, BasicBlock basicBlock, BitSet } protected static boolean reduceLoop(BitSet visited, BasicBlock basicBlock, BitSet jsrTargets) { + Object clone = visited.clone(); boolean reduced = reduce(visited, basicBlock.getSub1(), jsrTargets); if (reduced == false) { BitSet visitedMembers = new BitSet(); - createContinueLoop(visitedMembers, basicBlock.getSub1()); - visited.andNot(visitedMembers); + BasicBlock updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visitedMembers, basicBlock.getSub1()); + + visited = (BitSet)((BitSet)clone).clone(); reduced = reduce(visited, basicBlock.getSub1(), jsrTargets); + if (updateBasicBlock != null) { + BasicBlock ifBasicBlock = basicBlock.getControlFlowGraph().newBasicBlock(TYPE_IF, basicBlock.getSub1().getFromOffset(), basicBlock.getToOffset()); + + ifBasicBlock.setCondition(END); + ifBasicBlock.setSub1(basicBlock.getSub1()); + ifBasicBlock.setNext(updateBasicBlock); + updateBasicBlock.getPredecessors().add(ifBasicBlock); + basicBlock.setSub1(ifBasicBlock); + } + if (reduced == false) { visitedMembers.clear(); @@ -1209,7 +1221,9 @@ protected static void replaceLoopStartWithSwitchBreak(BitSet visited, BasicBlock } } - protected static void createContinueLoop(BitSet visited, BasicBlock basicBlock) { + protected static BasicBlock searchUpdateBlockAndCreateContinueLoop(BitSet visited, BasicBlock basicBlock) { + BasicBlock updateBasicBlock = null; + if (!basicBlock.matchType(GROUP_END) && (visited.get(basicBlock.getIndex()) == false)) { visited.set(basicBlock.getIndex()); @@ -1218,92 +1232,103 @@ protected static void createContinueLoop(BitSet visited, BasicBlock basicBlock) case TYPE_JSR: case TYPE_CONDITION: case TYPE_CONDITION_TERNARY_OPERATOR: - createContinueLoop(visited, basicBlock, basicBlock.getBranch()); + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getBranch()); case TYPE_START: case TYPE_STATEMENTS: case TYPE_GOTO: case TYPE_GOTO_IN_TERNARY_OPERATOR: case TYPE_LOOP: - createContinueLoop(visited, basicBlock, basicBlock.getNext()); + if (updateBasicBlock == null) { + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getNext()); + } break; case TYPE_TRY: case TYPE_TRY_JSR: case TYPE_TRY_ECLIPSE: - createContinueLoop(visited, basicBlock, basicBlock.getSub1()); + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getSub1()); case TYPE_TRY_DECLARATION: for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { - createContinueLoop(visited, basicBlock, exceptionHandler.getBasicBlock()); + if (updateBasicBlock == null) { + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, exceptionHandler.getBasicBlock()); + } + } + if (updateBasicBlock == null) { + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getNext()); } - createContinueLoop(visited, basicBlock, basicBlock.getNext()); break; case TYPE_IF_ELSE: case TYPE_TERNARY_OPERATOR: - createContinueLoop(visited, basicBlock, basicBlock.getSub2()); + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getSub2()); case TYPE_IF: - createContinueLoop(visited, basicBlock, basicBlock.getSub1()); - createContinueLoop(visited, basicBlock, basicBlock.getNext()); + if (updateBasicBlock == null) { + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getSub1()); + } + if (updateBasicBlock == null) { + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getNext()); + } break; case TYPE_CONDITION_OR: case TYPE_CONDITION_AND: - createContinueLoop(visited, basicBlock, basicBlock.getSub1()); - createContinueLoop(visited, basicBlock, basicBlock.getSub2()); + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getSub1()); + if (updateBasicBlock == null) { + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getSub2()); + } break; case TYPE_SWITCH: - createContinueLoop(visited, basicBlock, basicBlock.getNext()); + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, basicBlock.getNext()); case TYPE_SWITCH_DECLARATION: for (SwitchCase switchCase : basicBlock.getSwitchCases()) { - createContinueLoop(visited, basicBlock, switchCase.getBasicBlock()); + if (updateBasicBlock == null) { + updateBasicBlock = searchUpdateBlockAndCreateContinueLoop(visited, basicBlock, switchCase.getBasicBlock()); + } } break; } } + + return updateBasicBlock; } - protected static void createContinueLoop(BitSet visited, BasicBlock basicBlock, BasicBlock subBasicBlock) { + protected static BasicBlock searchUpdateBlockAndCreateContinueLoop(BitSet visited, BasicBlock basicBlock, BasicBlock subBasicBlock) { if (subBasicBlock != null) { - if ((subBasicBlock.getPredecessors().size() > 1) && (basicBlock.getFromOffset() < subBasicBlock.getFromOffset())) { - boolean condition; + if (basicBlock.getFromOffset() < subBasicBlock.getFromOffset()) { if (basicBlock.getFirstLineNumber() == Expression.UNKNOWN_LINE_NUMBER) { - condition = subBasicBlock.matchType(GROUP_SINGLE_SUCCESSOR) && (subBasicBlock.getNext().getType() == TYPE_LOOP_START); - } else { - condition = (basicBlock.getFirstLineNumber() > subBasicBlock.getFirstLineNumber()); - } - - if (condition) { - Set predecessors = subBasicBlock.getPredecessors(); - Iterator iterator = predecessors.iterator(); - BasicBlock lastPredecessor = iterator.next(); + if (subBasicBlock.matchType(GROUP_SINGLE_SUCCESSOR) && (subBasicBlock.getNext().getType() == TYPE_LOOP_START)) { + int stackDepth = ByteCodeParser.evalStackDepth(subBasicBlock); - if (lastPredecessor.getType() != TYPE_GOTO_IN_TERNARY_OPERATOR) { - while (iterator.hasNext()) { - BasicBlock predecessor = iterator.next(); - if (predecessor.getType() == TYPE_GOTO_IN_TERNARY_OPERATOR) { - lastPredecessor = null; + while (stackDepth != 0) { + Set predecessors = basicBlock.getPredecessors(); + if (predecessors.size() != 1) { break; } - if (lastPredecessor.getFromOffset() < predecessor.getFromOffset()) { - lastPredecessor = predecessor; - } + stackDepth += ByteCodeParser.evalStackDepth(subBasicBlock = predecessors.iterator().next()); } - if (lastPredecessor != null) { - iterator = predecessors.iterator(); - - while (iterator.hasNext()) { - BasicBlock predecessor = iterator.next(); - if (predecessor != lastPredecessor) { - iterator.remove(); - predecessor.replace(subBasicBlock, LOOP_CONTINUE); - } - } - } + removePredecessors(subBasicBlock); + return subBasicBlock; } + } else if (basicBlock.getFirstLineNumber() > subBasicBlock.getFirstLineNumber()) { + removePredecessors(subBasicBlock); + return subBasicBlock; } } - createContinueLoop(visited, subBasicBlock); + return searchUpdateBlockAndCreateContinueLoop(visited, subBasicBlock); } + + return null; + } + + protected static void removePredecessors(BasicBlock basicBlock) { + Set predecessors = basicBlock.getPredecessors(); + Iterator iterator = predecessors.iterator(); + + while (iterator.hasNext()) { + iterator.next().replace(basicBlock, LOOP_CONTINUE); + } + + predecessors.clear(); } protected static void changeEndLoopToJump(BitSet visited, BasicBlock target, BasicBlock basicBlock) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index e23e207a..332b0f1b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -55,7 +55,7 @@ protected static Statement makeLoop(LocalVariableMaker localVariableMaker, Basic return statement; } - int lineNumber = condition.getLineNumber(); + int lineNumber = (condition == null) ? Expression.UNKNOWN_LINE_NUMBER : condition.getLineNumber(); int subStatementsSize = subStatements.size(); switch (subStatementsSize) { @@ -279,8 +279,9 @@ protected static Expressions extractUpdate(Statements statements, in update.add(expression); } - if (update.size() > 1) + if (update.size() > 1) { Collections.reverse(update); + } return update; } @@ -337,6 +338,10 @@ protected static Statement createForStatementWithoutLineNumber(BasicBlock basicB } protected static Statement makeForEachArray(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { + if (condition == null) { + return null; + } + int statementsSize = statements.size(); if ((statementsSize < 3) || (subStatements.size() < 2)) { @@ -502,6 +507,10 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake } protected static Statement makeForEachList(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { + if (condition == null) { + return null; + } + if ((statements.size() < 1) || (subStatements.size() < 1)) { return null; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 38ded31b..bd669ed3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -33,10 +33,7 @@ import org.jd.core.v1.util.DefaultList; import org.jd.core.v1.util.DefaultStack; -import java.util.BitSet; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; +import java.util.*; import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; @@ -263,6 +260,16 @@ protected void makeStatements(WatchDog watchdog, BasicBlock basicBlock, Statemen } } + protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, Statements updateStatements) { + Statements subStatements = makeSubStatements(watchdog, basicBlock, statements, jumps); + + if (updateStatements != null) { + subStatements.addAll(updateStatements); + } + + return subStatements; + } + protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { Statements subStatements = new Statements<>(); @@ -598,6 +605,12 @@ protected void parseIf(WatchDog watchdog, BasicBlock basicBlock, Statements stat @SuppressWarnings("unchecked") protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { BasicBlock sub1 = basicBlock.getSub1(); + Statements updateStatements = null; + + if ((sub1.getType() == TYPE_IF) && (sub1.getCondition() == END)) { + updateStatements = makeSubStatements(watchdog, sub1.getNext(), statements, jumps); + sub1 = sub1.getSub1(); + } if (sub1.getType() == TYPE_IF) { BasicBlock ifBB = sub1; @@ -605,7 +618,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st if (ifBB.getNext() == LOOP_END) { // 'while' or 'for' loop makeStatements(watchdog, ifBB.getCondition(), statements, jumps); - statements.add(LoopStatementMaker.makeLoop(localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps), jumps)); + statements.add(LoopStatementMaker.makeLoop(localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateStatements), jumps)); makeStatements(watchdog, basicBlock.getNext(), statements, jumps); return; } @@ -624,7 +637,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st // 'while' or 'for' loop ifBB.getCondition().inverseCondition(); makeStatements(watchdog, ifBB.getCondition(), statements, jumps); - statements.add(LoopStatementMaker.makeLoop(localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getNext(), statements, jumps), jumps)); + statements.add(LoopStatementMaker.makeLoop(localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getNext(), statements, jumps, updateStatements), jumps)); } makeStatements(watchdog, basicBlock.getNext(), statements, jumps); @@ -649,21 +662,21 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st if ((sub1.getType() == TYPE_LOOP) && (sub1.getNext() == last) && (countStartLoop(sub1.getSub1()) == 0)) { changeEndLoopToStartLoop(new BitSet(), sub1.getSub1()); - subStatements = makeSubStatements(watchdog, sub1.getSub1(), statements, jumps); + subStatements = makeSubStatements(watchdog, sub1.getSub1(), statements, jumps, updateStatements); assert subStatements.getLast() == ContinueStatement.CONTINUE; subStatements.removeLast(); } else { createDoWhileContinue(last); - subStatements = makeSubStatements(watchdog, sub1, statements, jumps); + subStatements = makeSubStatements(watchdog, sub1, statements, jumps, updateStatements); } makeStatements(watchdog, last.getCondition(), subStatements, jumps); statements.add(LoopStatementMaker.makeDoWhileLoop(basicBlock, last, stack.pop(), subStatements, jumps)); } else { // Infinite loop - statements.add(LoopStatementMaker.makeLoop(basicBlock, statements, makeSubStatements(watchdog, sub1, statements, jumps), jumps)); + statements.add(LoopStatementMaker.makeLoop(basicBlock, statements, makeSubStatements(watchdog, sub1, statements, jumps, updateStatements), jumps)); } makeStatements(watchdog, basicBlock.getNext(), statements, jumps); diff --git a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java index 84963cc2..24cb2b5c 100644 --- a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java +++ b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java @@ -768,6 +768,11 @@ public void testJdk170ForMultipleVariables2() throws Exception { checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/For", "forMultipleVariables2")); } + @Test + public void testJdk170ForBreak() throws Exception { + checkCFGReduction(searchMethod(getResource("zip/data-java-jdk-1.7.0.zip"), "org/jd/core/test/For", "forBreak")); + } + // --- Test 'break' and 'continue' ------------------------------------------------------------------------------ // @Test diff --git a/src/test/resources/java/org/jd/core/test/For.java b/src/test/resources/java/org/jd/core/test/For.java index 847fb185..975778f8 100644 --- a/src/test/resources/java/org/jd/core/test/For.java +++ b/src/test/resources/java/org/jd/core/test/For.java @@ -490,4 +490,25 @@ public void forIterator(Map map) { } } } + + public void forBreak(Object[] array) { + System.out.println("start"); + + for (int i=0; i 0) { + array[i] = "null"; + continue; + } + } + + System.out.println("array[" + i + "] = " + o); + break; + } + + System.out.println("end"); + } } diff --git a/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip b/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip index f7b963517e248f0b429f6085da2804cb082c121c..b93697f54cb2385e25294e354dae871ea16032fa 100644 GIT binary patch delta 2660 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 SlMxaVlaLZa2GtM%0000-4Grx8 delta 2449 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 P6O&#OLk0&B00000kb0p$ diff --git a/src/test/resources/zip/data-java-jdk-1.7.0.zip b/src/test/resources/zip/data-java-jdk-1.7.0.zip index 34f1e7373e5336f046d184f8bda1a0eb4bf684b8..21fd562aa5b44380ab0fad01e40a1f6d99e85bb0 100644 GIT binary patch delta 4610 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 Zl2LZR?~6~nCkwbR!doFMn{B|q^FJUW%~=2d delta 4325 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 Date: Sun, 30 Jun 2019 08:37:11 +0200 Subject: [PATCH 033/211] Fix bug on 'switch' statement recognition --- .../util/ControlFlowGraphReducer.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 7b553429..4763cad5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -495,10 +495,8 @@ protected static boolean reduceSwitchDeclaration(BitSet visited, BasicBlock basi int maxOffset = -1; for (SwitchCase switchCase : basicBlock.getSwitchCases()) { - BasicBlock bb = switchCase.getBasicBlock(); - - if (maxOffset < bb.getFromOffset()) { - maxOffset = bb.getFromOffset(); + if (maxOffset < switchCase.getOffset()) { + maxOffset = switchCase.getOffset(); } if (switchCase.isDefaultCase()) { @@ -519,7 +517,7 @@ protected static boolean reduceSwitchDeclaration(BitSet visited, BasicBlock basi for (SwitchCase switchCase : basicBlock.getSwitchCases()) { BasicBlock bb = switchCase.getBasicBlock(); - if (bb.getFromOffset() == maxOffset) { + if (switchCase.getOffset() == maxOffset) { lastSwitchCaseBasicBlock = bb; } else { visit(v, bb, maxOffset, ends); From c77b46e1f884ca700cb1ff54fd1087d5d8022529 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 30 Jun 2019 09:55:30 +0200 Subject: [PATCH 034/211] Update version to 1.0.6 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 11db6dba..b2d0cb5d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.0.5' +version='1.0.6' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From f7c66845fec88a06d874101f3dc75ad4a445e049 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 30 Jun 2019 10:02:33 +0200 Subject: [PATCH 035/211] Fix compilation warning --- .../converter/classfiletojavasyntax/util/StatementMaker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index bd669ed3..4a5b1a58 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -260,7 +260,7 @@ protected void makeStatements(WatchDog watchdog, BasicBlock basicBlock, Statemen } } - protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, Statements updateStatements) { + protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, Statements updateStatements) { Statements subStatements = makeSubStatements(watchdog, basicBlock, statements, jumps); if (updateStatements != null) { @@ -270,7 +270,7 @@ protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, return subStatements; } - protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { + protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { Statements subStatements = new Statements<>(); if (!statements.isEmpty() && (statements.getLast().getClass() == ClassFileMonitorEnterStatement.class)) { From cefe750dbf6012368678836ee847f3c80e423d25 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 1 Jul 2019 23:35:16 +0200 Subject: [PATCH 036/211] Fix #249 : Bug with switch case multi-labels --- .../util/SwitchStatementMaker.java | 22 ++++++++--- .../jd/core/v1/ClassFileToJavaSourceTest.java | 14 +++++-- .../java/org/jd/core/test/AdvancedSwitch.java | 37 ++++++++++++++++++ .../zip/data-java-jdk-1.7.0-no-debug-info.zip | Bin 5031 -> 7301 bytes .../resources/zip/data-java-jdk-1.7.0.zip | Bin 64357 -> 64508 bytes .../resources/zip/data-java-jdk-1.8.0.zip | Bin 67320 -> 67483 bytes .../resources/zip/data-java-jdk-10.0.2.zip | Bin 18745 -> 21413 bytes .../resources/zip/data-java-jdk-9.0.1.zip | Bin 18731 -> 21397 bytes 8 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java index 43562cce..28cbd215 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java @@ -125,12 +125,24 @@ public static void makeSwitchString(LocalVariableMaker localVariableMaker, State // Replace synthetic index by string for (SwitchStatement.Block block : switchStatement.getBlocks()) { - SwitchStatement.LabelBlock lb = (SwitchStatement.LabelBlock) block; + if (block.getClass() == SwitchStatement.LabelBlock.class) { + SwitchStatement.LabelBlock lb = (SwitchStatement.LabelBlock) block; - if (lb.getLabel() != SwitchStatement.DEFAULT_LABEL) { - SwitchStatement.ExpressionLabel el = (SwitchStatement.ExpressionLabel) lb.getLabel(); - IntegerConstantExpression nce = (IntegerConstantExpression) el.getExpression(); - el.setExpression(new StringConstantExpression(nce.getLineNumber(), map.get(nce.getValue()))); + if (lb.getLabel() != SwitchStatement.DEFAULT_LABEL) { + SwitchStatement.ExpressionLabel el = (SwitchStatement.ExpressionLabel) lb.getLabel(); + IntegerConstantExpression nce = (IntegerConstantExpression) el.getExpression(); + el.setExpression(new StringConstantExpression(nce.getLineNumber(), map.get(nce.getValue()))); + } + } else if (block.getClass() == SwitchStatement.MultiLabelsBlock.class) { + SwitchStatement.MultiLabelsBlock lmb = (SwitchStatement.MultiLabelsBlock) block; + + for (SwitchStatement.Label label : lmb.getLabels()) { + if (label != SwitchStatement.DEFAULT_LABEL) { + SwitchStatement.ExpressionLabel el = (SwitchStatement.ExpressionLabel) label; + IntegerConstantExpression nce = (IntegerConstantExpression) el.getExpression(); + el.setExpression(new StringConstantExpression(nce.getLineNumber(), map.get(nce.getValue()))); + } + } } } diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 89e6e0a0..96ea3dc9 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -1144,9 +1144,17 @@ public void testJdk170AdvancedSwitch() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 22: 0]", "case B:"))); assertTrue(source.matches(PatternMaker.make("[ 25: 0]", "case C:"))); - assertTrue(source.matches(PatternMaker.make("[ 38: 38]", "switch (str)"))); - assertTrue(source.matches(PatternMaker.make("[ 39: 0]", "case \"One\":"))); - assertTrue(source.matches(PatternMaker.make("[ 40: 40]", "System.out.println(1);"))); + assertTrue(source.matches(PatternMaker.make("[ 39: 0]", "case A:"))); + assertTrue(source.matches(PatternMaker.make("[ 40: 0]", "case B:"))); + assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "System.out.println(\"A or B\");"))); + + assertTrue(source.matches(PatternMaker.make("[ 56: 56]", "switch (str)"))); + assertTrue(source.matches(PatternMaker.make("[ 57: 0]", "case \"One\":"))); + assertTrue(source.matches(PatternMaker.make("[ 58: 58]", "System.out.println(1);"))); + + assertTrue(source.matches(PatternMaker.make("[ 78: 0]", "case \"One\":"))); + assertTrue(source.matches(PatternMaker.make("[ 79: 0]", "case \"POe\":"))); + assertTrue(source.matches(PatternMaker.make("[ 80: 80]", "System.out.println(\"'One' or 'POe'\");"))); assertTrue(source.indexOf("// Byte code:") == -1); assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); diff --git a/src/test/resources/java/org/jd/core/test/AdvancedSwitch.java b/src/test/resources/java/org/jd/core/test/AdvancedSwitch.java index 699b3993..fcc491e8 100644 --- a/src/test/resources/java/org/jd/core/test/AdvancedSwitch.java +++ b/src/test/resources/java/org/jd/core/test/AdvancedSwitch.java @@ -32,6 +32,24 @@ public void switchEnum(TestEnum te) { System.out.println("end"); } + public void switchEnumBis(TestEnum te) { + System.out.println("start"); + + switch (te) { + case A: + case B: + System.out.println("A or B"); + break; + case C: + System.out.println("C"); + break; + default: + System.out.println("default"); + } + + System.out.println("end"); + } + public void switchString(String str) { System.out.println("start"); @@ -52,4 +70,23 @@ public void switchString(String str) { System.out.println("end"); } + + public void switchStringBis(String str) { + System.out.println("start"); + + switch (str) { + case "One": + case "POe": + System.out.println("'One' or 'POe'"); + break; + case "Two": + System.out.println(2); + break; + default: + System.out.println("?"); + break; + } + + System.out.println("end"); + } } diff --git a/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip b/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip index b93697f54cb2385e25294e354dae871ea16032fa..e1ba30d9dd19810ae553680d35fd8107abf11cd5 100644 GIT binary patch delta 2222 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 WW`h8o?PKhb*wkZP9izWSu>Sy&e0dZA delta 2940 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 diff --git a/src/test/resources/zip/data-java-jdk-1.8.0.zip b/src/test/resources/zip/data-java-jdk-1.8.0.zip index c90249387cbe42a1d245f1d6d0441bb9600c6b2c..c997c33121f1d973ea2f7863e549b7bc34c39d8e 100644 GIT binary patch delta 1888 zcmY+EdpOi-8^_IKoH9AhOb)4WTr{r^)UJx%X;6rv5JMO#n_-zrvM6K4Yz@ZY!3cFZ zZ7CYYao=if4)4n*G!{G5Ru(mlkdQ;l`}14ZUf28lbAP_y?{nYJ{nxXUfi23!X5GPB z-yfxkgxdiM^-n+=&|J6FR(l4$`1tKmKJ87+nAM;ayP4=N~OnJT{X05ReT!!iy>Q{4LVdJomim4fK4f0KB7-~ zpnJY z#!8qc&qzmt>Y0ID!vej6Q00j!-fy)P9`%o5MwPbPtSJhDV+^F2I?c)E@h+G=UW570(Qj^A9uH(l*%?)# zWz3%kts1`^_1;VtyC3?Ln~)wXYH(~xbfNYx%vCPA1Q|4c8_Rly;64Eo1iG89ff84>GMEX5rXKH@& zT@!`63QGPex$fa(8&lDBmmVwG`|?sdZP^NmCW!kbcpxCIJTWiqeA0-fONP2@xjI=I zt?jPkdQzqE5AjYnGX8n%A|t9xnPJxx(0|+LQ2i?<58mbms|bg>m?gZU(%I{AX_UPZ z2Pwz0&A(8p7q77Vw%o8+F>JoyiI;42qSRM(&M)Xx>TcuylP0c>3l}u+Ms=`N!ZddD zbU)O*%(ppwr7v+MI77T9Gaq_s!#?1aw5!CuEpXI+F8F9T{!4suVjVFh#?hNNa&si& zd834|))tyzRx~8l7L9yUD@ngXNQOU!$Qg4w!oQ-2NO=1F9j6Y8B;wW*NvKD0h{0Au zzbWR?9x0x|=BbPCYe!?7T(MU1_&;kdfwETNP#T1@JfpV)r;@E`LEO5--eHeERzOx+Kf1b zvDtbFtPEkd+ar#W5=&k8S?3{J%9c#!MNiqgX#Gi#iPRciLlY(HwwC=k`MiQZJ+^sd z>oMaX0~0;wQNmg0`SEXD_S%|>YZgsfSi!5|=aN&d83f;Csor8~J8Io@XmcGi44CUI zc%w1y?4M<}E!m;}!Q!S3#KDFcFANdRz9T{NcQlMUO8M{nzzGc~=HTJySyiYp>kH_b8&V5q&ia8F z{Duq#%Y=U}W)W0j=6f2L-GYoaf|xmPV4;g*Jc1m31Y>~)33VdoeE`c4#n_8*|(mwbC?k*G`e4qnhjlRmaQib~#X&~GVl?98z07FI5 zz!3-amI6VQ{Xg>B5*_3^Zb&VtyG#QUhf#TP*&m#6g{><(aCX@T*tsL93;SqlkiLq8 zmsY5NaSXANfSMOl4B#zKBGQh7YbzQsW|aUdKW+!I6KMa-kA5II06}f&x#|Tpg3t#Z ztoi`ANEC;^(}D*+(ZGBRDwASx@HQg9zKF`i&nl4k*$YrEZOAC#n}i?%eU!OS%(_*VvMwWn*sdo#E^H4GI5X02O!EQ~i0<{)UCC&PpRyWDkz!%$U_ zC6C!FXvSdlz*zxeTIK@`4fqtUcL^c^<}~mwUT65WNKb&1N3wt$XcjMzWa^~|Zxeiy z$9RF)73*6HLa`V>;9ZUKAQr;_ViCH1fQTpvQb79Kn^EoFOoYB4aDp)fWXp>K==}qV Y$V|&oH2?QYRY8j)X0Kw|TRG(X52${0zW@LL delta 1733 zcmY+Dc{G%39LMKNXC*RWQjI|+$@vHG8)7b64`D|d(CaL6)}&RVw5Z; zSu!I>mWmcs=r%ZXxJcYeCrepMxHGTrx!wOh-{o1}_c_0ei}bYz%UF|}9PBK(aFS`-a z1K9Gu%iXol$p~VDLjAT^b&%93sTIp(90c!+lm)#?x}li=JlLo_7iE=&|7z<`*k3Je4%dB|Q#Yq1;r(f8zJh!zeb&;na|u z`MdMu8ZiOZ%lh1GOFd+$j}5YR%yq4eP7Vp3>drE3sVvy_nK=@3X%~BgrMh(#8!T3T z&DK5L@W@e-bHS(L?2AQuG3QQY=1!{CSP*ik!|{>&ItM=7lWVB+QiIiIhQ@yO+%v6P zx4pKp7{24|fri_g8YxCBEYCQw^IX1hb)B4Sl6zx6>U%jbkv(uxUO%d(LGK3H#Bn$> zHhb>6)5x+uV%)<@&9kYw`MEvR_s3l;hHRMzX4!`gTMY+i-|E#3rnQZ#PrNZ*l__$| z>@+v_<%Ha6{=_|axx&KE@kiFc(QIyx$;M8aHoRUrw41b_ZrOXO%|{HJM@~ODkq6moxtv%aPMMumA9AI-aJ?iBenf4UB%k_iCf<8 z^|_|Jz3l!-M0%-9LfC!ckk@)QH_>B~piO*NF_;(kyt7vG@+RUouf?UM0{F*x5Ze9Gb;vg*q_>T@stG_5&IXDs(-W9Kd1Nv89&QdiOQ+s%~3 zD^Buc(^w~mSG(Vwpw&;O%?exYYMDg$>a!L-5DPaS$=hhWE@)%UzQD8vr1YicA%iNY zf|kbuk46h!QSO4<)t3Yn0ZAPF_LH*iE;4vk91bUk`&dM!;{(@)%ON*cRvJM3LD^M|7s?<(K$sz6Ykr9gLI;(Z64v5t;*s58UzUWI z@w4!VCveDxF@>sp1zBVV5Z;k6m7gdp>8~!8-jpX)lm0P2iGa`$Z9ap590HwUX~OR& cNKQ!X#lFX{Pf_v=C_jRT7!c-$B(s702Q?JxbN~PV diff --git a/src/test/resources/zip/data-java-jdk-10.0.2.zip b/src/test/resources/zip/data-java-jdk-10.0.2.zip index b419a35a0348d431853de6055347bbe9aabd042a..ac021dd2c90802f85daf94bc6c88d874050bc40c 100644 GIT binary patch delta 2702 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 delta 162 zcmbQboN@Ie#tEx7FX7B~p1g!pXtJWO;^dQ@+>`hE`7ur8p3Li?$MjENvV*qxWNj&~ z$@BdEn4SuQxvT+kOdMih=Dz^W$#(KWlQV;OCUXV}Ox_$|#I#KUDwV@DNgB-DufjWd zLZBa$meS-0f!Rzulqa9lkpb%QV|r&ad1p`)({{7Tw!vO}{0#gIHEawFGo2WK007xF BH2VMm From 09f5e6091edd2311ffa16bdaafc072f35941fff8 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 7 Jul 2019 10:14:54 +0200 Subject: [PATCH 037/211] Fix NPE thrown when inner and anonymous classes are missing --- .../converter/classfiletojavasyntax/util/ByteCodeParser.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index dd933e82..c68725d6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1732,7 +1732,9 @@ private Expression newNewExpression(int lineNumber, String internalName) { if ((objectType.getQualifiedName() == null) && (objectType.getName() == null)) { ClassFileClassDeclaration declaration = (ClassFileClassDeclaration)bodyDeclaration.getInnerTypeDeclaration(internalName); - if (declaration.getInterfaces() != null) { + if (declaration == null) { + return new NewExpression(lineNumber, ObjectType.TYPE_OBJECT); + } else if (declaration.getInterfaces() != null) { return new NewExpression(lineNumber, (ObjectType)declaration.getInterfaces(), declaration.getBodyDeclaration()); } else if (declaration.getSuperType() != null) { return new NewExpression(lineNumber, (ObjectType)declaration.getSuperType(), declaration.getBodyDeclaration()); From 4ca89c92692fb74738814ed8d25c4f7cc429ebee Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 7 Jul 2019 11:26:11 +0200 Subject: [PATCH 038/211] Fix JD-GUI #252 : incorrect integer constant type --- .../javasyntax/expression/NewExpression.java | 13 ++++++++++++- .../expression/NewInnerExpression.java | 4 ++-- .../util/ByteCodeParser.java | 2 +- .../UpdateIntegerConstantTypeVisitor.java | 17 +++++++++++++++++ .../jd/core/v1/ClassFileToJavaSourceTest.java | 9 ++++++++- .../java/org/jd/core/test/Basic.java | 4 +++- .../resources/zip/data-java-jdk-1.4.2.zip | Bin 22059 -> 22116 bytes .../resources/zip/data-java-jdk-1.5.0.zip | Bin 39738 -> 39805 bytes .../resources/zip/data-java-jdk-1.6.0.zip | Bin 55625 -> 55695 bytes .../zip/data-java-jdk-1.7.0-no-debug-info.zip | Bin 7301 -> 7885 bytes .../resources/zip/data-java-jdk-1.7.0.zip | Bin 64508 -> 64576 bytes .../resources/zip/data-java-jdk-1.8.0.zip | Bin 67483 -> 67546 bytes .../resources/zip/data-java-jdk-10.0.2.zip | Bin 21413 -> 21468 bytes .../resources/zip/data-java-jdk-9.0.1.zip | Bin 21397 -> 21451 bytes 14 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java index 4f0e558b..5ae16c2d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java @@ -15,6 +15,7 @@ public class NewExpression extends AbstractLineNumberExpression { protected BaseTypeArgument nonWildcardTypeArguments; protected ObjectType type; + protected String descriptor; protected BaseExpression parameters; protected BodyDeclaration bodyDeclaration; @@ -29,10 +30,11 @@ public NewExpression(int lineNumber, ObjectType type, BodyDeclaration bodyDeclar this.bodyDeclaration = bodyDeclaration; } - public NewExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, BaseExpression parameters, BodyDeclaration bodyDeclaration) { + public NewExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, String descriptor, BaseExpression parameters, BodyDeclaration bodyDeclaration) { super(lineNumber); this.nonWildcardTypeArguments = nonWildcardTypeArguments; this.type = type; + this.descriptor = descriptor; this.parameters = parameters; this.bodyDeclaration = bodyDeclaration; } @@ -59,6 +61,10 @@ public int getPriority() { return 3; } + public String getDescriptor() { + return descriptor; + } + public BaseExpression getParameters() { return parameters; } @@ -67,6 +73,11 @@ public void setParameters(BaseExpression parameters) { this.parameters = parameters; } + public void setDescriptorAndParameters(String descriptor, BaseExpression parameters) { + this.descriptor = descriptor; + this.parameters = parameters; + } + public BodyDeclaration getBodyDeclaration() { return bodyDeclaration; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java index f4d18589..53dcb7a6 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java @@ -14,8 +14,8 @@ public class NewInnerExpression extends NewExpression { protected Expression expression; - public NewInnerExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, BaseExpression parameters, BodyDeclaration bodyDeclaration, Expression expression) { - super(lineNumber, nonWildcardTypeArguments, type, parameters, bodyDeclaration); + public NewInnerExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, String descriptor, BaseExpression parameters, BodyDeclaration bodyDeclaration, Expression expression) { + super(lineNumber, nonWildcardTypeArguments, type, descriptor, parameters, bodyDeclaration); this.expression = expression; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index c68725d6..437b24c2 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -763,7 +763,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau "".equals(name)) { if (expression1.getClass() == NewExpression.class) { - ((NewExpression) expression1).setParameters(parameters); + ((NewExpression)expression1).setDescriptorAndParameters(descriptor, parameters); } else if (expression1.getType().equals(ot)) { statements.add(new ExpressionStatement(new ConstructorInvocationExpression(lineNumber, ot, descriptor, parameters))); } else { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 56d9789a..075f115a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -205,6 +205,23 @@ public void visit(MethodInvocationExpression expression) { expression.getExpression().accept(this); } + @Override + public void visit(NewExpression expression) { + BaseExpression parameters = expression.getParameters(); + + if (parameters != null) { + String internalTypeName = expression.getObjectType().getInternalName(); + String descriptor = expression.getDescriptor(); + List types = TYPES.get(internalTypeName + ":" + descriptor); + + if (types == null) { + types = signatureParser.parseParameterTypes(descriptor); + } + + expression.setParameters(updateExpressions(types, parameters)); + } + } + @Override public void visit(NewArray expression) { BaseExpression dimensions = expression.getDimensionExpressionList(); diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 96ea3dc9..eb2b5a48 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -110,6 +110,8 @@ public void testJdk170Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.indexOf("()") == -1); assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); @@ -144,7 +146,7 @@ public void testJdk170NoDebugBasic() throws Exception { assertTrue(source.matches(PatternMaker.make("System.out.println(\"hello\");"))); assertTrue(source.matches(PatternMaker.make("String str1 = \"3 == \" + (paramInt + 1) + \" ?\";"))); - assertTrue(source.matches(PatternMaker.make("String str2 = \"abc \\\\b \\\\f \\\\n \\\\r \\\\t \\\\\\\" \\\\007 def\";"))); + assertTrue(source.indexOf("String str2 = str1.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); assertTrue(source.matches(PatternMaker.make("char c2 = '€';"))); assertTrue(source.matches(PatternMaker.make("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');"))); assertTrue(source.matches(PatternMaker.make("Class clazz3 = String.class;"))); @@ -156,6 +158,8 @@ public void testJdk170NoDebugBasic() throws Exception { assertTrue(source.matches(PatternMaker.make("this.int78 = 50 / (25 + (this.int78 = 789));"))); + assertTrue(source.indexOf("protected static final Integer INTEGER_255 = new Integer(255);") != -1); + assertTrue(source.indexOf("()") == -1); assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); @@ -2285,6 +2289,7 @@ public void testJdk142Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); @@ -2324,6 +2329,7 @@ public void testJdk901Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); @@ -2363,6 +2369,7 @@ public void testJdk1002Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); diff --git a/src/test/resources/java/org/jd/core/test/Basic.java b/src/test/resources/java/org/jd/core/test/Basic.java index 598c17ff..4afda88f 100644 --- a/src/test/resources/java/org/jd/core/test/Basic.java +++ b/src/test/resources/java/org/jd/core/test/Basic.java @@ -182,4 +182,6 @@ public Basic getLast(Object[] objects) { public int getInt78(Object[] objects, short index) { return ((Basic)objects[index]).int78; } -} \ No newline at end of file + + protected final static Integer INTEGER_255 = new Integer(255); +} diff --git a/src/test/resources/zip/data-java-jdk-1.4.2.zip b/src/test/resources/zip/data-java-jdk-1.4.2.zip index fb1dbc40d5e6ee9b83a71d1801ebbe8238a02722..b2f765e0a998d9f7000bd3cd441550dfed1f5f0d 100644 GIT binary patch delta 2961 zcmV;C3vTqQtO4Y#0kF9R5xQ9CPG>*?rK}170B92c034IiP!yBi1r2`(SR+Lg{+Cpi zRYE{fK@I1r5EML+=tr@@Sy03h1#?)4$pSe;7B`D}_TGE%U9p^c9v+9~?7jEid+)vf zGn)hiEa7A3?aZtHE4z>UaqArbYVe1O>#)#+>pi$ZMILTc;lLslYvQJSY=FgL85NH= z3&tfXR>PP$Tbhq?+~R-5ttxKA?OrVN;0_f(eM0hn6%XJ+ zA^wmT53AfC@!(M}9`oXH@$`fT2Mhiuy?Dxlr@eT_i)RJd&2+*@?bJS3fwGl?<=Tu? z+KQ&Eu4r;tccJ2ehRsgA)KuV38may{bs3_5eFdKMfMHqujT%S@#D6%e@>RD%M$fjBFEE^B|=O=)a(~R#XZwaW^U_fZa)9_ zq@kX65=nm|)gvf1Eg3t9lRPSlnR?XHZP`stGrB;*+LhC_R?TQhNi)fDBWw)n)_}~~ z29?v&HiKl<47qhNxc&AcV8VNPnUIwl)3@zoO&LQvfj3ODrDJ@s;b$;zQ%?^kEwV6< zIFrw-lFF*-ChZd4flPEe#?((^X&vtClO^dCs$_p%3A9Yz8a7iMENXeQ6$`;WnrjTR zmgFIuV1-FAbSJEVY#FaL1DG?q=U`gsWWR28MAHmt-O9r0 z_(&{!XxIT^4Lf2d4IkqZ4WEkJ&v2rKF6`vN=Ni7im#nb?(e@sErQvIQ#OHnN39#bK zB}0b#Kub$N!#DU=EZ;HOz{VQB$0;m~=pKKufH$B8)WC9q{J^Y$ClJ^BH2i=cJ@`q( z&-g{dZrGheTd1!Q>T7KE8ZH+&_@7S6IjM;ZGrOro zOb=AB*7Q_d!*=Mb4p|Er`^<%>p&L7Eh=_k> zp1`#S9h@rDCcVIazJ^_}EBjO4CXCv!d`TttvuASQlytMC`wX))IwHgW$W|Eci6Ule+PF#+R_J!jxlV}N=Mes?ZlgacJ%0A6IIV} zOoj4wkxUWf=+F@1Rj|(g>ipc)DXV{M|Cd{@Wn^>j*;~B4h3{)sPHW?tXG`%UEC%=r zi&>&-3oK(N`f9dC({iA;RkaB>+Wy52cT!LFTLa>~F>IQ8%Gxn8sBe=i2FH*;2G!R(hJq!~Zj#Q$x%%Oh zMx3Nn6vKxS=;Fjygg*3hS1^z>(nd*fSF{+*`IjF>5GP(MS+DO zmv8Nm+qdsHR*8h1k&r7Aa)&&NQT8AT{pI6WH8P5_5x990X;dSP`HkLxxLnS)468*P z{?)?~r#}#mG!{l0mmfz(q)}@uaE5%&+trA}xou;Sdl_btvLDGTDHne!m*aLd+~`*t zizfi6K>^p*8GZn3U>4Tqx(;SzJ(kHPsAeMTaVi?H3?bZw4J1I1*dW*dNor3PfI=Nt zA&EicQO89{k#bPqc`z^pC$*l5y-2yR9yOYz+_Z2g(xg1J6NiP}nTQ_h9VV5JoeBNk zq*Rc{;Fw)N(i$8)84~&tx8jCLBPjkb`nv97wNxxRB8tgoByT zW%S|@TJ+;CdV3iCE9QPUj>yzYn7-u+G;E}+iCreq)l9B$<1wtk42Kuxz;nw=X_TO> zXp7pQNa{!o@?MVpjDZmMJRu#Ns$-)G9sECrVL?*IG8lz_$K`*DdS0fe1EQE`vzUW- zW6g6>ARgDs)cD#HH7>QfxV947xddi2lwwPI*FLG%1G!p1K3D6_aLe8p%i8hP`BpA+ ztPpALO|~4N#LHTO!N|?<7AX()&ST?7nnm{trXab*NpF&if%glcZl8aHPMt2!SmVbth3qUi_GT#_#>sUOb8rqP)@8i8nwqXB zMoZ8yQ483}jCuuEZ*MMI$HH8=jaZ&*lHsOE z8FXogA)6>;pUq-$YqMw8Ww+F_JL>6dD?4I)1{}c=GPE5ixgx_mNrXWurwEA8t7p$d zAi2PM?7)Aib$$DmIxFRC#6is~%NK`>_b20&3>X)aN6hi2OlNhBqqe0y?-CTV$JRR! z9%Td`lBJ8vPupl!pLz-0Bhac>W$$&5{Q11R$p*`Syj+jrdK@&?ZV^$hpd+(sa9x@V z;WQakkR~-cd8%-cw}m_(k~wU$L!pLx%AF2H$rpd$Sh5$+!r2+8Ycf6O9LJpNr*!Ux zllsV+>!WjU?o`^@GUwuir6(00C$?4{m>G(WKEN z{sl1A6VR+8OYTaly^8bmYC>}jYvDSAaKofgQ)L^K)CF=}DGcbMjQOqMkX)tJ55QY} zhn;^Mt-AUSXS|N@f~hlX@g&8iImM++`6WWJ_<+qQ-jX~5eYLt=C}KG;oT6*#q&`z~ zx>Q@2q`DBMgjalha~E1WGw%9><4_iL+y+O4z&Mw}b*GK681H|xQl0gf&lL zLMUK=x6s1Xx!D_~1@W6xf(<#2O3*ke#!)}>C^jm=#-rHO-#Uu663iXN=C@&s2hr=wU7pVG)Bh!&H<6d;p}77CNiQcePK7?Z&iACo*&Q~|}4kyCF0n6cdwBEESW3RZarBM3cc36O*t+3zP9xGzM=^ H000001Awnt delta 2910 zcmV-k3!(JntO2X60kF9R5gbB|PF}>FrE>}Z000vJ034IB5EYZ(1q^>@SR+*wJwqzP z=!OtQ1vRXw5EPWv=*NNu)`B9IC>XIYCIdu61}B5=uDzGFch_FAthz2Pi)HP-_uhN& z`p556&wG;u1T5j>y*uySd*8k1p8IB=`s42V0Mz3*6*pkShZ}vkNktKER^h@eD%Qu6 zVr+q1#c-Q=yj>_RRk42#?htFsiZO~i{aCJI3@iK?_u(!TrC8#}-D18+4EOr6Qq1@H zalf#9K*fW2NSHtD$0I7|M}2tAkH`IZLOea`!$P6|lpjy~@QfeN`th7le_jkPc;Nih zyl}WMdQl873A2|~#`KE!=-z>^u^QLKD?tKkTtB7p6)WNY|6~+)jm&wvXg>U+RRMW z)-!gOo*p(lsCsPk?asK`Qs7OSnf^^1bHbd>6!@|Ore$v)rD05gCzY|c*phO)l#|AM z1w}(CE(p&C)v14Qz@W}$zwmItU@D_v^+a0FW~&d<57n#FdZxcRW?QLDzk<>ZvDP5g z8rp=;Tm{9k1sQw5uu};}(VWVp?5z~IYHGU_xZBJm&zRMb${3x)g9jScp8A1lt^_;G z1hdqwlz7f9y6u5fR>2w_rq$nYP_iLmT1JCyWbKAlJ)3_@%%!6ti{b8Qq|;`%X{D12 zw4}jUE!`$sv~}0Ci*uC}#jI^@Do&b+*vVq9v)4!<5}Q)DO$hR7juocVap(~rgkO0whyVIfNGr5jQIGt`(uzt<|t6I@~ z(s1_FjZV|v-W<*(x0|0ZhD5(e%}p3Yb0VEQ z5%!0*uo_+^TpXSq_Jxy1pN8-7y$?TV_z{0UX^3MVUdY0Iy>MUexYuxnz#%a8Sh`P| zybZIGa8mJD94AixnX#~KEW2PeQDIg$lS&xjDss)pBsJ`Ub`70kxD1zTI16WM_(crA z;#_t?MqUseV{ph`z}#mho`yZKmxeAebPHVfMmsxDo}DrqV)7M}TIk%mv!)c3r0st* ztxkPVFo5*j#mHv$em<-=6Z^Ux4(BY(YNpfCX&=X*PriY6?fW}?3$nH`$o$P=o2PW- z!`w~W^*qPW2j|lD49j#VUkK?8Vbq6)2%v(E{#S1o?v;v~_J7&++h)GHzC*>USH!+S z&9p|H`SvKAgv9_~QVCn|vcxv`Vyu5wo1T?dW?OBW2&3&^!tkbzOus!K-VDQ*Wn}C< zQ-j7XsdPG(MHRN-CzOI6P=ZSAh<3_50sP+D8In$v$tXFyMX!ljw40n`a+ZXVb60Ne z&aLk)?fjw_=(h*rS4xSE%W;1`b@QW6;anA20dFL*<#PBUfzIXdM|$WOu}#+Dlfu^5Z4~O2c_{92nNf>5UOzZj$yUn>J-ONzRO14!8OLQ zW@kW;x=X`LqMpEpQEy=WIM#oPN8RzLCm!`iealesIA#Sa$FX*N6cr=zawXoR#+!

nN~998iqt*OKv4Y==B<1Y8EO{LzIm`%xfq_UJe zlsv9`)mT$dX)2olpdKY0*Jb))tcTgykmE+E#wMi4HmD<(b8rqe$4Y-h@c_1v06pb^ z-~c40J{F#I&R3eTTS@j|M5%^d{yq`lVw7Fj;C-ujZ9v|7C)UY zf-~9hXEDjM*>C5{q#`_0W00rI5Ube*XRy{T5k@W*KLbCNmWom=zMf<+oI`6T==xmG zxyP~Tty4Pp@=1NIn4Jx=P`Q zbY6cl#n*~SeWn(Csg5rx#n{V5tlJfWQqpT@F5F;b9Lmy;d*F%_821Wz?spIt*Zbd2 zsVhY6WfiW%)p9k+E*_BN=8q>_o44Sl08mQ<1e3v07_+eus6Y)ILXA#d z#GR#c3IG5AlV(vp530b8eZcY50jj`_eZcY5ld@4W0$dQ2u@EMc4N^`5r4*B~5EGMd zQfdNE7L&0M6O(XK4U_y*SOPd0ld%vJlb{$9lY3K60*o1x;Ta&4>r+kws~(fF5EGM5 zR9ynBACmzfACt^fP6DbXld%vJlP^_c0wFAuu@DoJi7XY9yj4yDfkczB5EGLhRzC(d IPXGV_0K|cu2><{9 diff --git a/src/test/resources/zip/data-java-jdk-1.5.0.zip b/src/test/resources/zip/data-java-jdk-1.5.0.zip index 73a94a0c681e7b5d74ddee052bb88b1e6c3a109e..c78f41c7c7ea9026461eb2c61ccb918a98e65c40 100644 GIT binary patch delta 2405 zcmV-r37Yo0wgUaO04D6&0~UoUJU0RamWHjf%Bcr(nH|4JtG& zQm|31n*`acV2fC{D%gJ}G`FkRft@mTDcG%Gk4igxW$Y6o`xP9JaZte_1&4)$BZ3_D zAoo!V%wnN*OvZ5)4Y5dUP6+O#AX^1Fr82P7-sPXaIUfaQgy)kA&dNAfu%Z>1I^M1& zYkwKhvuS1F?!33F=b5@WFxnKm3$EofAh?U36?u8FyCmbXiXMNsA~siLT$A9-7?!Cg zM;TVeOs7Wn>nTC%FQIggbSh)(DSMQjoNIVc`)%7^TTfaNyvcNGTFX{>rga+$a%Otk zvfGBK7?t2LQ+B)dee3QU@%^H>oUCe1Qa5=!+OJfc^hUc)D~ zYTH&q`GGU^d3t~Iq@J4AykE*TrWsZTI_zksOuMrLSEI(GB)EH|6Es(LpqVlT&z&{J zutw-plHz2xMHhXIWHLQEZ6y;Dw1g2)>XvSsOp2O~`UwN&;+CP?M%1SGv~HHAFO<-* z(J!uZHys*}`}2$uC(_aMEW@78t%P>J>h(zKnM{YjXf=N>E<`)3>C`!H44KM`q-Prp zGi|YUnK(DOVEgfgu_l-*PXdh^|1BW5kPyWY;;LoXbFI`s7T7uJ&m!cGdZy>HO3oo0 zQsI{@Mw|9@VNIws_)8uB>Q$a**aP*9Eum?nUo##uWrh*Asgt&*HJ_1a9#30FbKA(+ z&AaOvGfsa^g_`|xSgG_k)u@wp$9OW|bv2rvYsHP;rifm3tTYo!8pdLrhQS!3VJL=a zxQ-h#ZfdxN85(Y5x`yExCgYBVyU4Pz(*-hQ+|zI$54fM714*Ug*>#_5CKHBeMeAUv zPC*S1@ko%z1az>Ah9{W80_s!ZK_#dK)nMsh$zXq-pd3sXQ#CxrGa1h{yueG&SaH*| zkVs1?nJLs>LmUa7j_W5pyrNHn!m@v;{;Uh1Nghn{iXjUJ7Ah&X!u zD-LhcNKLb+OQ=?m`x81H#8WxfvW%2H!klFcGLuO&gW71#uT}}YQ3}=32Yt!+!)uU6cs<2H%A%6w1P#g~!)D3-4XXHvtMxAobIwFzY6#qC5=-cr)>b$(AVLm@Ib- zioawQs#r^L{b`~MT%=W@pc>Vy^K=p>=hZ(!Mu6+lN6=#TP}*N6i?Y?+le6&o%aP5( zKd8xQfBE|e4EE_^ce&t|u*cUh?Dc;wxQ`04usas^#KPXNTpkr;5j7Sm8BrXzwC4#I zm%map=Jr>P#v)~7kuvvDB^J>lrQBhk`>`5xxrao`d7q#vx!jh*4(B1~aXnU}5x*2E z|1*_lC`DR}i3Cv>bZ2=)Fo3O{g|;||Fpi)dwRB9$rOKTLC4_%=F0vx} z$|qgKM15VdsK#ugH-0$tI)#nEdExR#s&W-ZN`#8bbtW}_w54ypEkV(a>TE~o1!^2b zDY31Y?^3Pbx>OM!((de1Pn0E6D$zzQ^yBT+Lbs%f^d)+kEm-xn@>MD4su1fqIoWBA zl&IDz6pGz}tDN+H@>s$u)=__8O9+K1B~B(MNgNrsBhk^}$GRsAzM4;+-Z8XBlBx-z zYGew+ydZlEK~*1r8^PPCO@6$p7x>x%)G>3X8$y(y+_8E&d|O3}@`{ds<~kVVNe4n9 z7vN-7!Em-Q${LR3436T@XjU@Dx{t+7a`ULQilE;{TzINq37}s0koyU0#9X1M zl0}2ChuPHDoqQ^ICQts6hwI9ZM7qOAnq(p=j#-+?%w{9!Fd>T=&9H%UiPCw*=|VKc zA~eTRB6Jz`R`9u4#T0+n(2|K6x!|c$!kPCDkI<0FY&7sb8h5H*;snYQqoG5PrSp)< z7Tu`6t8)#XdIH|_(28ng(PZ@bZy%kTAHg+1Nzx4rZj<=80OhcSZ{IeK%XS8{gMsYi znCy~DiZ574YZg-ZK&t2Q>%NbsSBoM2C}|qAi%SO3?0PZDle~YM11m2X<4(*@2ERcJc10kibc71=f*Fo)PziWmbE!Y?mS<@3ry!C>wTHEy+)}F?7W-i za5-)&6}^R0^fXsAt*Gd!JJISnS{I+&TcrH+Bd=VCs$#;_qUu7Jt-n%C{vPW&|Hqu` zlop?s0kq*T1Q0&HEry}}ZA1d-a2uWcoo}N{09|jR`y=#-aVqYi=WX=5SuD4*H18At zlEF`iSH?kpMIGYn_K;EwoG+(^-?PLmx?~Q!Sm#awO@XH{2mk;o4wHQ7Ydllv~Ko2 z>INt+PHjVaOXT-kk;4k=Y43`-fpOH5#ju5+ryaaSg0dMBa~fU>^YxCo=ZFH24%t(# zj`A-$$Cn;?BWS%$G&sjfyZys&VJS{XltXv4z&i z7)$T3dZJgIF#6=uw`srU49`=1ANCxa)3sDS#lESo%Zh4fK-wd@{6ni#q_0gg6nIDE zMWJW-TlvB@RV`5j7yef0f$wS-EuqDl#=y?@esbO_k!>;t#WO% z;1J$tC81~IsX^8T6UwmF!^k3zp-*68K|kL=Z{p(})y`wxOkyQk z+&FZH+;poIgORh&(B&=o&#yQtyfjnpgMOrLUi5T(X69dCwMFlW|GNlYEuIe}SN!es z81lPtz!5%U6EyyHmSWvkSb9Qr&SR~5G@8Hx3OG%%E0ke=Q-ML=2))AOB=t@R+4-&@ zIPL;7wMI8eH}u5nPFjX{6sJKJuhUJupQTAwsw66+-~rkLDf9LiPucl8t;g z4gs|u$&l4n*FF|3BW^|5w39bMOHI?Vdg7mMY)qoyf1VN#Kz6;UD$EK-vrsni@py8H zXzKh;_iZP|0n0ZwbF|GccCmehQc98zL=vGcspYbbyjz5f@#?Z0e1ViTjj#EzUy2B0 z8D20Qp6!n-aQv~@PcV=zb)hI|>FJ;$+hW);nr~x{fO@Ci#m=XVqsKe$60v6d#C>c2 zB$fUC4cg$xf}cL|bM0}jyr`7~JM!3b#7`Y;c9M0LL0}Hws8*7-{izT#+4RKDc`-6W zttTX8d6t{gxk$Eb6Ok~jo(vmouLUzrPLTSJRgYB?v4$U#&&H6iXPUtxhCf=BJjeNT_J6?** z6h=Jpk3WnyAElGLUMmkfm__z@5w-360F3_AP_tCwb?7n)3X>l>3%#X3cEo`VQ+sf; z9CJ`UG~usV87WujJ#3Ii_ILJks*IZ22>x+Cbj&ufqwL|%^atzmypyXid}1bn9Q+5O z5=O*B-Hc#@u!N~-y<*44_@~Dz)f_r?U_^N}HV#_W{XD_;&bvVTQ}T@J;i`}19OlO* zFA2eY>iw6?c9}gGLiG~W$TS=8#3Hi`2L{h=#Vl@Nos>+_2PTM@o~SEp)j)0mf1X^5ezPkg|B_gz79 zD$mO5ObAzXXskS%Ec&UF7s0k&O%f7Z*KKZaZ4;enHWj#ItNIyD7wf$UuA8!t`{X&0 zxBEj~mR!!0SP`*aryqvIWaEzfcweFQ_?|hf4o{N*M;7CR&jf_9Ox>B7<9z;>)gq~5 zOhSh%z>V1w;F>Pkc20$g{)^BDLBOKswL`1V9NZe9K4-}k2yTZIO#XV#62O-|%$5oYtedSNvIim{IlrF&Ajtt}L} z_BiB5KJ#1^GCr?%3qCsZGKNr(>zhMYzFz7-D>43dURLMzoOh2gi_&NFf)suFW@Byo zPiEdm#Ldd}GKbyb^x4fHR@Z;C2|>_MJ$*#P@_6rlyIvR$ z8FocMS}DnSr+re^c1T$_V=#ZjtACaVcfRCctNq`N=?bTA)(<_0A$o6^(aK?FT-D{z zD4ipvL#1Li3>gitYl5|R3o*B!2d|&DgjWFAZ1Q(TThi6YwgY3L0q2d8&796}MlMfd z+Y-*0=n0hiA|Q{_{T{jN=$f-?M#Gd+EkYE(eMw9yFiyg5ioY@`{3-BP;zVr264K&e zpXIfVOk|D+doL*jV8heAF)5%XGYN9}6Q7;brb zo$TWm9!b!Vu9_}0MAzI4IUcFOXzf+J0M|}RS8D`OAbIKPSfs3s(bQ{P}Rr zzEPju3p<)$g2^SzG`eCt&X+W;pW<}gK?*y2BO`U_lNvvjKZT|0Uw?;PR9~+ZLK~pL zxh#_u8K=vt*6W6*_)N-A>1%BuN85d(Tq(Uq|AYVkJpf+jp%2k#B$A$d9|8SpKp8-S zyWqh4JUQS$da{6Ljuem#V8B%dK*#=ut4fxYNz|T>?R0^1+yMVV1 z_cYQ-8gS0H2Pc~X9ac(!Am1HqZnlS~3NC|DXZKJaBL-9zTmiRO{!&$d$3OwG3}p}z zpfRGsw)lSsML@OC1>9=8cUR9&9H183gYUZS>8{%$090fT$^{&YBEW~e0jDB4V5G}G7`ucu{^#|4z8~-RHEas~c2NyYRQVe3}N;o$yh=uo^}(8yf3 z35j6n*kC1?we}8D|Jm|%eNxkueiiV*?VV|lt!3#v%7<(B(-pr0v`p3P`AjqZ?ygp3 z2mjg7=V|*}(U0h^sua#U;KGEBs}PkcujXaA(mg{oJ3s>7)G>6DZuiz@wp)yOt_YRa z_r!fT6IW<=nk~(fmms*bmQOc+WVJ1(qqE|dR<1UeEo8)U7pQxEo-L~Ru^Zat-4b(U z_Z5m~7A5+NFRvA=*s`pY$w<4?xcN?{O|d0!!BFT+h`u1zd@C(hec-LBOC#lNK&h8Y z)QS%ywuQ5doZG)BDEIMu_Np;4akAKTGiofT4nSSc;hV0Ix2H#x8_3Ax7@ zQJPZSkyfZIhO1$*Fp|YABn){y!NC$?In877D6|&Zln>&JoB0+z8?c+JmF+TUZZur` z-o{bkWk1ROo@;j%^kP#2)Y|kZwi*QP*hanqe8UxVgX9`b_+EzxhU7U9%JIAm%6Huzn#FaY!y{tp8xH{5G8Hcb( zoh#R#tT9Z)8;x00q}HXSFiJgCxFvGUm6Z3>K6!tv^DmC6C-t^$+w%GsrsNo3k(Pd% zt7*Kmov!5+&SC5<1B|gbwrBFSDK&Hn`Hvu`Gk$gn;?C?x+~l9J@Kf&j_3B1paM|GW zm!W34l^4lXHWRkqQ#P;cU1kvFJ7grv#Ghm*D?nti9$^f z>>0+*RcAeJ2STLGP*q1-U*~iGqJDDlx;o4}~we4{^GbJ2VYaNWe z)TeL$JB$Ors;{J_Skjy`CcWfbzk-8j}!h zZXo)8UbC>InfztCZ?&dJ8;|r9!EI`&W(w7Ej0sDzzr4ikEgBCKjD|oPWhnU8@j-l3 z$epfzs2ZLRs@7Qw4Xb?qC>;fhNV)S@!`Wd!X|=0g`P5eSuGH^J7mJHzz>y-9YJ#`7 z1C8CBepN)*2bN8*InQSrh5ZRhmD~!1un?S|dkDFbAC9Dfwzk(xx5|B0jhgGsDa+=^ zSV4*!G%+y2#E%Kvr`^*aZpt@HYadsVWJ}|@Dx9Or3_hsyT!*cTW}-a(%42tmFN@Kv z%tz4NxStpEocSP@$;yIn;-Q*nNT-$F#Hy+L8FVOgIl0IpdMc46coXX&g;8Jr&F(rw zq#){K#8)Cd(+{iowB95qWtZesaJU*Y`mep2666-O8Q5u{IqLLxAE-hz=md{Ah&M6@ z?{eMCptoH1V@fp)FhnKz|9B~f&8d(GOR80p)x=uuAH8eB;3Vyxb?4REhMq zAx_iLBz>|j_7bwxTD~1|pdMl}0eQ9ZfD^)6Z zILCkUNz;W34TFQ5EqnWFQWh6IlER}KCuVI}7fV@%C8s?_U*~B9$`zWr=Z0Dsb8kBd zQt$r+0=nnzAUi&*0~$7Q@=_yVx~nBG2y86e*D6E=W1}`0N%>EL^&Zu4hrfX6_v9tF zr0gS$)(9OzqHd^?e8Oi2Mq)A}kI1|eRJ7;?>=BwNVz7^?@V>W@4pb<4Ovmh+CPmV=oC(iJ{4OMUHYa{(vuyh z7tl31SEs>8G2}(^<~W#=78|(~dg{i3rWYr}<$ibkl}cpm${5#x9yJTR5NIyM7!+#? z5$zpLh>hH*h3bZu_%fg$$7Uf}yF^UXy!2C(b@$xo&lKvG){r}X}vNlv;Mj;xt@ zdMVuHDHGInEjylX&;4?+8p*crpCA(z9>m8Pml5S_>={b=uv7erPb8v?QkMNHmQvdF z+tQr8ZFGIp^HE&W>D@AW$cMxAr()2_fizV_iK>_+rgfDxX_w1&Z|QUG%r&ZMog*zq zAU92V9HTe=$5)uO8?xwE-#ZB@myfo$Im4JR*JDuak_W0)mX%2n?dY3%=G8``>3Pet z*rbo$d%tGR*|iBH*^rSoD{PZ9^rVdvZMv4VXGT5q%@he;z9LMP1P@aqSJcFbkC3>S zmw5D2?#@E_@6|ev3@0<|bEn#Pa{ZSk4r#`5Tjs<0u~M3s?vtM{i-a~~3d}yxh3rFY zxrR`QNKpxCy$t(TBF6U1G`-<$WBoKeY{FU>S80N()hXyo_r4a@tD1+0W1syGYE$?} zKO&Q_aK>!7)U{_1-%e0`p`gv`DXa5oB>=m#U7voYhi~_!rGW=SQ6_s~HN!yBGhWKK zC2sRyLI!KnFuk9IOR`;s=_|@-wKqC+lMpymtm(Jg(5Lh_8n`(hJFQ>Kf7^G>UrF9~ z${%a-1@UoBB2Ok4qp&yk`YtE@iAb|8Wrd zYMf{GyvsPRRiixNvA2SI+QfrODVk@!b>rC=haVP9EcaCEq!o~f^n@hYW?{WIcOr|E zP)3rgTpC-=y7O>aQ&?1tfJ&{;W~+%S?m#o7Bvfn9@M|ys`Gf~rUsyx9GS-VfrbM{k z&|#Npvlhl11l!tD_($r^vTTwWf7mVhm-P9UoD(oNf8J(lsNTkXxO9czqr1v%cDs#= zx!m=$zL1M8EENjNmh5?YaN=3NgCEO1HB?qBt|v;xuA48;NvO`Xi*=MR&&_T0iX6Y+k4$2(P z>&3ib;l4!sRRI$e#xY7It%ftTH)TKqmCrT?5MI1`kgE4t7Pi>F)n1SV4SgqQv8bA4 zTFzGD6~d3~=A=Wl2RECR>mt2@ESsZDV_SK3j9wFx~c;xQQ`cVz& z#I!$rM|bFn~v^yI$@#uDX#czMtPyz32asOi6S6P}_o4$0Kfr-{pJQ$MU?NN9twuC~FCl+a6vU5M0@U#1S;bK&U^ns@n@8OMzUX6Qj^+jj z$*?~=l3>~xKhPWdr!55bj3IzL^zkuQC`f=c?HHd^>`x|R#vcGNPyaY4m^$uw@*eng M+!VUfe&SF42fsJ})&Kwi delta 3025 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 A8UO$Q diff --git a/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip b/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip index e1ba30d9dd19810ae553680d35fd8107abf11cd5..9d0e82372df66fa62d9f26973041bc6ef426988e 100644 GIT binary patch delta 1969 zcmV;i2Tu5fIn6z=7zh$VSm#c|nC8bj2LJ$y3;+Ne0FzG}9)FEhRnyZz6g{D7lZF7L z6t}`KNQ+Bhic_o%UaV+C8z2yxk_LBocXxL_DDFDE^E-HEV1T=6ihje8hrM@qubw@- zdH?mn6966XPC|Vw_L8=Q4NKW{nS|w7A)y9Vvb9xSti~Df{j`*=X}`9+S@{IiWdb2UAqGUPi1yLS)Dc!)=AcuedK_LT7iGYKhW zYC0$e<)9R-6!Zog2ZdlpohIWco(Xs^<9`KS(uMjnG)2f59K87w$TFrPO{){)EW<0x zNt`gPAFe;UC(>uNv>I$gXQgH{G6rLyj3I1T03vXWzuTBLO*LiAMpnja8YsaV8E=sz za%AV~IwezQ=Pc%1{;9}FV3dr}Y#7539*co=d;YqR>?Eeh7>6Wr(%#jKHVOMJ(SH^( zJ{OPHCO+Nh=H=anDt{~$sWeoX&7KMS?HD%gcR&~BEp;}5Va&DYI0l#U4rgxwA)qR= zyHc`pmMNh9Q0Q6mE05S?2x}#mBb158|HXWVGL*1h^Z38EMaw8LL72y$Q`S|}=6`X$ z{M%LS7m#MqvzE3PO)FZ)XsXtXDSvtUnTWNBu{vV^s>7qJ+3D5{4s}a*e^aL`dnxCd zrkb@zX|vTKnyzbkG(rdZk8Y=FtyU^K1;r^l3^yu}Y*@?^CO@ZvFct0VSwLN?JaNNzv|k;^u`)^KSRr)737Yu< zTPFv$AcLzO!4-Or`Ug>wO&d5UHe@K;ekzT0LN!U9_5;or@W4f~P=5;HYwxRF)m1&& zEv0u~!)5Ar4~3Gq;i}5LOO2HSsP*NtAAy|e+q)(KTlHMqQ##(W8Lx}8C-Rf1vw^bBTSkbN2SPAFp znBnv@k8t*ooKWhADt|bGnswc|LlF7y=TWt8kNWNuDI!I!(B0l}*SiuxlRhE-G3qB> zp@djK(}s2^`YIN42LlC(05J(N*sJE*}eV=p!p7W5y^$Tb@_WZXG_J7Wg9JS#20#U%MFQ~@F z1nBsJirgoNoR|GNY&!!vC$-OE1b+{$t~%h%f%)fd0IjdHO`7LnIlH}R#+cS3{1#q+ z+rj4%q*B@)g2&(f#xGzXwge!^$k zKSPI~z9L*+*GWJD^Jz|hO2@qhIWt~L;d;#cHW=)-^`am2@6Ie(ssK6?Z32jtG1_z~ zLo|S{W$5njQHGuY^eRK2hlnMKKX=i$4E=7x{=NgVI}P*=4nkPxPQ#ey$2$iA0E!Hg zJsUh14~WgAqBPY34~WgAqBPY3$l&l}qBPZ$kQ*xkgAbFv8)^cf8Ivg-RtAe200000 D2(z&p delta 1397 zcmV-*1&aF3J%u^27zh$nQG!iS0`l$i1ONaj2mk;a0F!YZ6O%m%3x9o6+4IX#6#lLz zO&UR4wH6cGpo3bA>d#hN?bH@)qYXluRGQlN-58G^cr#Yt1CK;O*Y{6C;+azpPAY;9Z5|;)) zcE~7mS&?BX*oj>dc7MyTWb9EW#9j%ujH(1jhAX4S!|vmUC!+N!9p#8Z+3MjFAHN1) z$EVUX&(UC*DI zA;%(vXgU70>7*AJy45UFctn$6^sv2Z9AuEW=k}`QP>`JESpF=A(C9Ji8HBuBA!x6f zN8rV#ZMz#>&#o}26|-y`p5a?m7U4!0IJ|qsExJ|H-)%X&7^aP0w#V3Sq;135mCoBn zy*_jEPnM$Z5r1svm_I-aiWP7zn=5w`^P+E*_bxYTYmFVYN!7YFlM=fgajTc<(n?<- zH_!ANp0kYD1O%2)oh{RRw?V#vaXv-JmFWW6Y=0GJaF(Huv7@ZXnyM*U4=th% z(7hiO!4l)e9Arriq`%67?3i z2Y;U;s%Hc}BkGxOM(T~2o>la0Br6AM5Ah|5P&{7Lg?R6xp6#V)dp<=%&#Kw(LMAG_ zQ1pJ9o`LwA1d-)_PH-h{w!Ih`ReKD!m)yMOT(VT4FN?u3X=iVlc{`slfm-F22#l3l5k z{t%%Udtcf_t=DsOq&O%=C~hg)bOab7K;!~_lThM%GOFy(rOq;z%X%?I_)>0A3|~)EMCoL%MeN6PS7KG0k4?K4Cb_!9hkq)# ziGE43b{(?NbqlfNtifW56q%xS>k1ykLAMhaGLHylM9MeR2r~8&OQr9bLbt#7FalwK z{22n1$gmn~+L@#6VF*v5-D%fV#M<9q6Bv3oc$Km4`yeOKEB{6$Fq|5Yz{n%iY znoS4g9*WcfnoS4g9*Wcfx&H>`9*WeH*c~eZI}MX@9ut!o9#;Zc7n5-wRt7^D00000 Dib<7o diff --git a/src/test/resources/zip/data-java-jdk-1.7.0.zip b/src/test/resources/zip/data-java-jdk-1.7.0.zip index 8bdd229375fc09754498c329154744ea3e5390e9..d78e33d74a2999a9ba9b8e48dd85a876e3f0678f 100644 GIT binary patch delta 3155 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 diff --git a/src/test/resources/zip/data-java-jdk-1.8.0.zip b/src/test/resources/zip/data-java-jdk-1.8.0.zip index c997c33121f1d973ea2f7863e549b7bc34c39d8e..53c666dd52b2f5483251ee2c48f39cb05ccba173 100644 GIT binary patch delta 3242 zcmY+Gc{tQ-8^@cUEsQMLNw&$FFtUV*gBZqO%-FLHvQPG;31e5v4`b|Pn~*IbktI<4m;xDk{6$q6dt1fR>w zLYN6!bWn|7y&cB6A9u(rom({Bf%_(%2bMfsWhR=x4)zb~pY77V&lg9~*j;UYJ-9DC zmr(xjjTJJ;$*Qf5PeW<5H3a^Wy@zt(Tm;3tU#s2zUoj5>@9q3;rvb@PCf}P+tuzV0{ zHn1ZokW|IAk#4ul`?~qUsc2;X8cnKe7qRaXc}b99+?OWr@=9K{>A8cv%Vwah-CFdF zy2wNM^sZR~^;JmmO*4Cfd4Y@VkGwC(A8;p4*gmCesY=Nz(MB8jXgs6uR35;)1ULOr9O$?eN4Ui zp1OI}KM;eOZZ2-`_D{}FDNS4^25{I@)P?;sVD6jzY)&m|l+c8Ro8SEF!lKT~T^&D{2Zfm^M(1ML)N2a) z9K~Kf(P90r+!oL2#gnkLu6pK@U}JcZ<>f?wc+&y$lTT&2!?jU&e5PD#g_Mpa%srTv zl`WR`-qX#=3LskITEd#0gWt7@kOhs2-*fwiwbTh0{~Fj_;3|QXq9jrC%D5>H${z$y zE5-V7anFL9fJ~22D;J)P8gm4a@TVAmUc%t@DC>d=Q-L%iY?5NffH}OD!>_6;1NTSb`z2``@5aiDcghH1KY%G5q^%USsR98dPosx==FN{ za0&Mx)i7Tw@8aTd!ENA5>VkrSc0)yMJ^lhbU|EFK2O?F%f??xj9%rkLtv)}~t+9>i zk6`W^;4FxQ+u9haQA(5x&t}GY1lOYWrG~g~$!W`+&*te>Oy-$t$pB7~ieThG>6z0SVa$v^742Mo-&_@-=j(7ocP+BhluUJHm=-^oWr;eieXUXxqRIx&m&JGDryNts(?sicxwM# zqnhvbUVUO*Aa5y~wyVjo?k~>LW7?M_$!a}{5v_|}jcJKFyH4$h@|Q7Ne~P{Nup+VW zfH9|Sw>sZ2_RB>bjvl6jXp3O2tdgKLob2(P>!cn&D6&_VHKRU+hlWE1WiLaoIkV@X z5PdfnWh;7Bt!uuwiq;VB1CSz%9=hy{uH;}W*O1V+vNJz0*F@9^bm`DW0erD)ld6*w zwu)jVT%A|hAYJvY_l8O7H7Rt~kL9usS0c#+cJK<6eHhA#?EQRBLW}hPDYCwcz?Rfb zct37K00;-2t_{bhUGW&#?BF!*53{VTk&b9WRGTelEB|BPID*5=5YAV9N(3X>ubcJ4 zY_0rBj#!u2vEDjkzk411pSv76J3eT)=0vXaER`2XkzorG3wUZ>lEa>v-`{8-k<#QZ zc~He$E##q%_P|?V4JzXc2XPyUgp->laQ;%Jv_>*?&s0W7Ce)Opv5hTEG{x;XO8*p# zo1V4OQnTFYBtpIeC@8Ve^Wv%L-PPgVV?lG~lP4I5Wly-Ke&#Zhvrd@I5jO*e8})Gh z)<&aK$tu=BvaX%JFYJ1w)`{}|Y#}QV{!IDGeGa^G=jspKDbYAX`v*qrv&y2#8;X^! zCMc}jmJ}Y%%qp>i5pSY|M% z*SjxeOr>LeEg*%Om@<`Pp^`)kvoyqu&uyew8&f_mm}+UZ_9@Wy$mbXR*6T2{4zLdw z1y?jNgcM9TV?6ymUEWIU^oRIP;XnZnh1|G#9*uasQs%%}t!Y?iQZ(va_QjYs-N@Q9 zG+U(^kGZ&h%10cCsa>cWLLxASw! zIKj-n*)_>8`C?Q@SaI_giCMB^FEwGHsUABWHleQ$rtkTp(btUy3_~K)@0VXo^L;DM zdiw`&=pc*bSf*<2h*0QE{8EF0;P9D7m$W36iConsTb=m$b{}U%ldZR1ztbF4qvyqC z!f=IEVu3qYX&;kc*L7>C9rf6h;eA=k?Y~}nO=e$8!q-BBG|WggGZaZ)vnNI*al!h1F7y~Cu2*2vF^9ZH=4Id+M2M-7| zr-XQM?A_=E&3Kh!)0sE!dPQgFpu@G7p1tLA0q^Io;O(a$n}-Vjw5%XX?p@)d>6K74 zcR91*Ec@SHu>pN)M_+1Kk3?v!8j@dGSpQLa94}0LQ(4 z7yKGJrLa24ANz;0wj8*BAodMM1Ou4rxq_P^X@^rtlVuabTbIrox!r7=AM1hN8 z%fz)Emw|a_%VX3*UaC$2YD~)*7N+7(o{#)E%)Y1N6o-Hp5h#DH2qLEtdJlJ_s$+?pKnh=Hw>DKM3a_Eq#E^gA_AiZdu^%1Gm1904FEz?S$mEJ>AxR&KKhs@WJ$ z82wv;f^UtO!KXiwfV2q+F%bt9caT7~`R{7xE)$rwg9UC_{-fN1Vyl0M89dl!0Sl~n zK%YG*czllwY}!=?EYSa}`T}y;|Mn2WLcxq*NTA30p9~|o`3ntLUiq!SD|=WVJ@5!` z1oD8?JtP1RKa%?U4nWL}Bdp(d1_&`n7!)Hxs)j(IAo9QfLIUp{1OkF-*$_ww;CK5l zoCdvbbNx1`Wluqbfx^2WzCet05(2RWzGWV9G6WI`+{pUPU_{oD7fRA&gvgQ{fWsM8 zq$5`r0C5I#@{X9B0pbZ{6&$iAsh$CX1PY1{`7}w45#j+LOAq-Jse}=N2F_G~_*z~P z8xzDH$f`YL7%7$M(9hNMd+V7^e7~=Ybb=XT003>jQzRVoVT+E@Bc?JRF5^!>I;9hx T{qP~6qyQF(EHnMjV`r8yV@md2Cfht1OM{dd#=eZT>>_K6 zvJ~0ESYl*vk);R`Z@KEd-uL`-f4-k{-`Ba$`Rj}&u%sujRB|cv9M_454}@sBD{wF| z;dq&tM9AKUp=7R2PC~r(P0JHj(A_9XDpwxyur{m8h(I_goEGf>bkSlO&CWVtjU2^= zcr&=ZGlD8yD_jHk&zC>hU<55sJQIa|+F(cm0PMxolkLu*9@|U8S$p4hqXD;Yd;h_i zMy7(#ZC()wMlnvteIdK=>mFiv`>GG0EzJ^lcjN^0^W2-d@2PB>)ozJv)S$EsCK z+2uCqbcEE~w=oNe4zApTXGB|xNR(^Prp)*goblIQ^1XOYcEEQY*to2~5zSdpWTlaZ z1IqbgZ$_?V2!3_I+ZEvyit+t~H3h%Gri7uWZP-I<9X7h1=Ci0)?rbT0q-0m ztRnk|chFk|(S8#Mq@eYaKffpb?x{FL^MmO#lZvc*RjZFl0ZZ3h~!Me8_G=^ z?s;0H+ARi8MvZzDm3wkhvuc8!@PPyFz0K{`?@ewh=Ly#d5FZ;uiyNv+zqpOT+fqP# z*%`OTYI7H5q{?)m6yyAQ@q1_N79vABj6GaI?BpuJG74k+z^HRnC#m(1!_Zf1Fx$8fIRL-oj~)0NSKz~8{iSy-@65Ioniu)b#k(|P;4N<6 z{0UGbnnbi&W3F#7LH18mlpm*0vaaHzKttD??K2U?31UWuH^7@6;POOpaFvIUG_jR>@rEW1L<7G8Q!?A5vy+$rvn*BR0j%Pu%V z4o)vb$+twJCD<0~%EqscP4TxUNowPv9&Tx$!@Fwqnp@BE=67VAhLK~Bpl?YDC%PLm zgQiNRvwe>1^@J0}bCox6$m;X?q6l=T29g&9(X_{k0!cc#yGh>qd9*2SuJrdeW66fu;#J zq`nYqZ4HPI40VM$PBMEhI%94wI$&(%lvd;!7OPLgAYN%<5bx?RL4gOGuby{o5|f1a z4i!yXFlSHsmP2j@RXBQxn}5td=|Y$g__%aea1*pAO`SGZuPz9y@D@^bU!ul1@tmMt zwkEMixatjFd5dy;FC1Jlt2raaiD|Zjt8c=?P{zPsCDT^%=#j z@gi=%ka=_6wW1u8nP6kIqH9;dr+?Mt?R>VHmzy`Uoi$Y!5HoMkx87p=f5hGj;88eB zzL7eUsiNAe3d|{I_LzD;{eJX1lJMpZy8zMs>$4vvT5>|Au8Z3hxbD{iTQpJ0r+A5n z>p}}_ojb5==T2P3?G#IjXwUmdHK{+T4eHJaej1n_7%BE-Z!TKX{f2&~B5Q3ykgu5B zYO%@K<0S7}hVf|ig0~+nxex8ohIL!M_nAdUe#mQPeztaFgeUPCxeTaj}UeL7(p zeu`AzEY)fy4H2872PmQ9bbx?Bf+|(noWmK8C*Hx+VAl*^*h}Si-&zKXXv1NU4!t17(+(@zgcTbKOMeQ~VX9+h_c;z1I z#NqA{Bb6LP!rLest-c7lBK}UA9w`wb%;QZk2t^4NYP1u-XieuU_COUR{go)-NOJyb z^S9ni{->mq_;UFP2h4fJ;zLI$*0lBR`+1p3$RW6q`NQKc*e=A_v3j4SPfd!;4YjRJ zn~La%%H`HY4?L6Yx%~bW$mg(DW_0~!x1X}FjWkxdOJH0n0Y#U8TuRY+HmenFWKdi3 z>6D(q<(BD&oqwQQHNNtEWBsFoXd~RpG9rpq=2!;?x+`i=pt;hthGTM^k2wp4aII5m z*W`w!D+9X0AXv?D(-4uMlri^|6!%dm=SSN~E`iG&cG<`MDMB7u2%7Jaoy6TOS_{V2 ztJa`bcD4Mz-v+xu^<#CR_(^7yg0G9OvKEK%R40VDOefmmrewD^W3^M*)|@e*E-^cn zbCJ#u(>5cxv=yK@+PXAy@aH8O8-}407EU?MR1ble2A^m(6OIlr! zjI3*2@kYF9pP&h{PGe*veAn@@#kR)H7MG+4 z*GM^pdb>yUQsFYJnu}~EgT~_)4yv8Y#OPNguN5LpeB_vxUB<*#WMwO|Ndp{%p>eWy zJ(&;;&{SSUU`=cM+*z*Azpc>7@~|2z+ctm0f5F{MY_KAVAQLzLLxV1c`Z0|Dnh)Iz zJm{qn$&;a78Q^{E0IWmm$RZdZ-~sRxA5y zs7qRQ6n&=>eKoIP3+q|EZss;UmdU-ibX3*FK-Fb4v!NNI8zJ=`S*#R7+T3WsIEtUU z)W0_W570GV?{3|>l-XY!$c_xSUjUuC+-0i2QxXd)zZRSA|6+thvJrA=kf6-HKs@R0*Iu^^zck1LxlV2SP@JVXxOLVy&# zKaq>ftxR+wUKc_0tA4_SnZJ4_>m! zE*xC*-;ab{6nHUsA2ECE?B01#>m3*ZAT<{9 diff --git a/src/test/resources/zip/data-java-jdk-10.0.2.zip b/src/test/resources/zip/data-java-jdk-10.0.2.zip index ac021dd2c90802f85daf94bc6c88d874050bc40c..ccfb73ea5b855646c00f90659cb7c2d5c0d81231 100644 GIT binary patch delta 3023 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 diff --git a/src/test/resources/zip/data-java-jdk-9.0.1.zip b/src/test/resources/zip/data-java-jdk-9.0.1.zip index e71146f5ca0f79b50c3d051cf5ff899887d09704..d4c995eee2f92787495419dd64d50faded25c9ec 100644 GIT binary patch delta 3008 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 F007?`ycqxh From ad4d6fd2e081aecc645f52a687cfdebd5551e3cc Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 8 Jul 2019 07:23:26 +0200 Subject: [PATCH 039/211] Add jd-core-x.y.y.jat to JCenter Maven repository --- README.md | 4 +++- build.gradle | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8423df4..182feded 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,10 @@ JD-Core is a JAVA decompiler written in JAVA. [http://java-decompiler.github.io](http://java-decompiler.github.io) - JD-Core source code: [https://github.com/java-decompiler/jd-core](https://github.com/java-decompiler/jd-core) -- Maven repository: +- JD Maven repository: [https://raw.github.com/java-decompiler/mvn-repo/master](https://raw.github.com/java-decompiler/mvn-repo/master) +- JCenter Maven repository: +[https://jcenter.bintray.com/](https://jcenter.bintray.com/) ## Description JD-Core is a standalone JAVA library containing the JAVA decompiler of diff --git a/build.gradle b/build.gradle index b2d0cb5d..03e82c28 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,8 @@ apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' +apply plugin: 'maven-publish' +apply plugin: 'com.jfrog.bintray' dependencies { testCompile 'junit:junit:4.12' @@ -15,8 +17,17 @@ tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.+' + } +} + repositories { - mavenCentral() + jcenter() } jar { @@ -25,6 +36,52 @@ jar { } } +// Publication to JFrog Bintray Maven repository +task sourceJar(type: Jar) { + classifier 'sources' + from sourceSets.main.allJava +} + +publishing { + publications { + publicationJdCore(MavenPublication) { + groupId 'org.jd' + artifactId 'jd-core' + version project.version + from components.java + artifact tasks.sourceJar + } + } +} + +bintray { + user = System.getProperty('bintray.user') + key = System.getProperty('bintray.key') + publications = ['publicationJdCore'] + + dryRun = false //[Default: false] Whether to run this as dry-run, without deploying + publish = true //[Default: false] Whether version should be auto published after an upload + override = false //[Default: false] Whether to override version artifacts already published + + pkg { + userOrg = 'java-decompiler' + repo = 'maven' + name = 'org.jd:jd-core' + description = 'JD-Core is a JAVA decompiler written in JAVA.' + licenses = ['GPL-3.0'] + + websiteUrl = 'https://github.com/java-decompiler/jd-core' + issueTrackerUrl = 'https://github.com/java-decompiler/jd-core/issues' + vcsUrl = 'https://github.com/java-decompiler/jd-core.git' + + publicDownloadNumbers = true + version { + name = project.version + released = new Date() + } + } +} + // 'cleanIdea' task extension // cleanIdea.doFirst { delete project.name + '.iws' From 2c6de62b0777edffc99b33c1b730b43871039cda Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 8 Jul 2019 07:25:21 +0200 Subject: [PATCH 040/211] Update version to 1.0.7 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 03e82c28..e50044df 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.0.6' +version='1.0.7' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' @@ -36,7 +36,7 @@ jar { } } -// Publication to JFrog Bintray Maven repository +// Publication to JCenter Maven repository task sourceJar(type: Jar) { classifier 'sources' from sourceSets.main.allJava From 225e4d6b152e0c1284f77b586dcfe99460439ab0 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 21 Jul 2019 17:14:19 +0200 Subject: [PATCH 041/211] Fix bug on Long constant references --- .../org/jd/core/v1/model/javasyntax/type/ObjectType.java | 3 ++- .../classfiletojavasyntax/util/ByteCodeParser.java | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index 57fde21a..a1a9a95d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -15,6 +15,7 @@ public class ObjectType implements Type { public static final ObjectType TYPE_DOUBLE = new ObjectType("java/lang/Double", "java.lang.Double", "Double"); public static final ObjectType TYPE_FLOAT = new ObjectType("java/lang/Float", "java.lang.Float", "Float"); public static final ObjectType TYPE_INTEGER = new ObjectType("java/lang/Integer", "java.lang.Integer", "Integer"); + public static final ObjectType TYPE_LONG = new ObjectType("java/lang/Long", "java.lang.Long", "Long"); public static final ObjectType TYPE_MATH = new ObjectType("java/lang/Math", "java.lang.Math", "Math"); public static final ObjectType TYPE_OBJECT = new ObjectType("java/lang/Object", "java.lang.Object", "Object"); public static final ObjectType TYPE_SHORT = new ObjectType("java/lang/Short", "java.lang.Short", "Short"); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 437b24c2..79bfc349 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -1013,9 +1013,9 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in long l = ((ConstantLong)constant).getValue(); if (l == Long.MIN_VALUE) { - stack.push(new FieldReferenceExpression(lineNumber, TYPE_LONG, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_FLOAT), "java/lang/Long", "MIN_VALUE", "J")); + stack.push(new FieldReferenceExpression(lineNumber, TYPE_LONG, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_LONG), "java/lang/Long", "MIN_VALUE", "J")); } else if (l == Long.MAX_VALUE) { - stack.push(new FieldReferenceExpression(lineNumber, TYPE_LONG, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_FLOAT), "java/lang/Long", "MAX_VALUE", "J")); + stack.push(new FieldReferenceExpression(lineNumber, TYPE_LONG, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_LONG), "java/lang/Long", "MAX_VALUE", "J")); } else { stack.push(new LongConstantExpression(lineNumber, l)); } From 10adb3724d5a5486343ec7f102bc1e2f4b7a2ab2 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 21 Jul 2019 18:06:49 +0200 Subject: [PATCH 042/211] Fix bug on local variable declarations --- .../classfiletojavasyntax/util/LocalVariableMaker.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 8aa13e1a..641d0fd9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -182,9 +182,11 @@ protected void initLocalVariablesFromAttributes(Method method) { AttributeLocalVariableTable localVariableTable = code.getAttribute("LocalVariableTable"); if (localVariableTable != null) { + boolean staticFlag = (method.getAccessFlags() & FLAG_STATIC) != 0; + for (org.jd.core.v1.model.classfile.attribute.LocalVariable localVariable : localVariableTable.getLocalVariableTable()) { int index = localVariable.getIndex(); - int startPc = (index==0) ? 0 : localVariable.getStartPc(); + int startPc = (!staticFlag && index==0) ? 0 : localVariable.getStartPc(); String descriptor = localVariable.getDescriptor(); String name = localVariable.getName(); AbstractLocalVariable lv; From bf81c7e43f1d066fa042b25cca6bf3765acfd999 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 21 Jul 2019 18:07:57 +0200 Subject: [PATCH 043/211] Fix indentation --- .../visitor/ExpressionVisitor.java | 12 +- .../java/org/jd/core/test/While.java | 804 +++++++++--------- 2 files changed, 408 insertions(+), 408 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index a09255a9..cf97a0ab 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -86,11 +86,11 @@ public void visit(BinaryOperatorExpression expression) { visitHexa(expression, expression.getRightExpression()); break; default: - visit(expression, expression.getLeftExpression()); - tokens.add(TextToken.SPACE); - tokens.add(newTextToken(expression.getOperator())); - tokens.add(TextToken.SPACE); - visit(expression, expression.getRightExpression()); + visit(expression, expression.getLeftExpression()); + tokens.add(TextToken.SPACE); + tokens.add(newTextToken(expression.getOperator())); + tokens.add(TextToken.SPACE); + visit(expression, expression.getRightExpression()); break; } } diff --git a/src/test/resources/java/org/jd/core/test/While.java b/src/test/resources/java/org/jd/core/test/While.java index 32389682..b341fc27 100644 --- a/src/test/resources/java/org/jd/core/test/While.java +++ b/src/test/resources/java/org/jd/core/test/While.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -33,405 +33,405 @@ public void whileTry(int i, Object o) { } } - public void whileTryThrow(int i0) throws Exception { - int $i1 = 1; - - if ($i1 == 2) - throw new Exception("2"); - - while (i0 > 20) - { - try - { - $i1 = i0; - i0 = i0 -1; - System.out.println($i1); - - if ($i1 == 3) - throw new Exception("3"); - } - catch (RuntimeException $r3) - { - System.out.println("RuntimeException caught: " + $r3); - } - } - - return; - } - - public void loop3() { - int i = 0; - - while (i<5) - { - System.out.println(i); - ++i; - } - } - - public void whileThrow() { - System.out.println("a"); - int i = 0; - - while (i < 10) - { - System.out.println("b"); - i++; - - if (i == 3) - throw new RuntimeException(); - } - - System.out.println("c"); - } - - public void whileReturn() { - System.out.println("a"); - int i = 0; - - while (i < 10) - { - System.out.println("b"); - i++; - - if (i == 3) - return; - } - - System.out.println("c"); - } - - public void whileIfContinue() { - System.out.println("a"); - int i = 0; - - while (i > 0) - { - System.out.println("b"); - i++; - if (i > 5) - continue; - System.out.println("bb"); - } - System.out.println("c"); - } - - public void whileIfBreak() { - System.out.println("a"); - int i = 0; - - while (i > 0) - { - System.out.println("b"); - i++; - if (i > 8) - break; - System.out.println("bb"); - } - System.out.println("c"); - } - - public void whileIfContinueBreak() { - System.out.println("a"); - int i = 0; - - while (i > 0) - { - System.out.println("b"); - i++; - if (i > 5) - continue; - if (i > 8) - break; - if (i > 10) - break; - System.out.println("bb"); - } - System.out.println("c"); - } - - public void whileTrue() { - System.out.println("a"); - int i = 0; - - while (true) - { - System.out.println("b"); - i++; - if (i > 5) - continue; - if (i > 8) - break; - if (i > 10) - break; - System.out.println("bb"); - } - - System.out.println("c"); - } - - public void whileTrueIf() { - int i=0; - - System.out.println("a"); - - while (true) - { - System.out.println("b"); - if (i == 4) - { - for (int j=0; j<10; j++) - System.out.println("c"); - break; - } - else if (i == 5) - { - System.out.println("d"); - continue; - } - else if (i == 6) - { - System.out.println("e"); - break; - } - System.out.println("f"); - i++; - } - - System.out.println("g"); - - switch (i) - { - case 1: - System.out.println("h"); - case 2: - System.out.println("i"); - break; - case 3: - System.out.println("j"); - } - - System.out.println("k"); - } - - private void whileWhile() { - int a = 2; - int b = 2; - - while (a>0) { - while (b>0) { - a--; - b--; - } - } - } - - private static void whileTestPreInc() { - int i = 0; - - while (++i < 10) - { - System.out.println("1"); - } - } - - private static void whilePreInc() { - int i = 0; - - while (i < 10) - { - System.out.println("2"); - ++i; - } - } - - private static void whileTestPostInc() { - int i = 0; - - while (i++ < 10) - { - System.out.println("1"); - } - } - - private static void whilePostInc() { - int i = 0; - - while (i < 10) - { - System.out.println("2"); - i++; - } - } - - public void whileANDCondition(int i) { - System.out.println("start"); - - while ((i==4) && (i==5) && (i==6)) { - System.out.println("a"); - } - - System.out.println("end"); - } - - public void whileORAndANDConditions(int i) { - System.out.println("start"); - - while ((i==1 || (i==5 && i==6 && i==7) || i==8 || (i==9 && i==10 && i==11)) && (i==4 || (i%200) > 50) && (i>3 || i>4)) { - System.out.println("a"); - } - - System.out.println("end"); - } - - public void whileAndANDConditions(int i) - { - System.out.println("start"); - - while ((i==1 && (i==5 || i==6 || i==7) && i==8 && (i==9 || i==10 || i==11)) || (i==4 && (i%200) > 50) || (i>3 && i>4)) { - System.out.println("a"); - } - - System.out.println("end"); - } - - public static int whileContinueBreak(int[] array) { - int i = 0; - int length = array.length; - int counter = 0; - - while (i < length) { - int item = array[i]; - - if (item % 2 == 1) { - counter++; - continue; - } - - i++; - break; - } - - i++; - - return counter; - } - - public static void twoWiles() { - int i = 0; - - while (i < 5) { - i++; - } - - while (i < 10) { - i++; - } - - i++; - } - - public static void whileSwitch() { - System.out.println("start"); - - int i = 0; - - while (i++ < 10) { - System.out.println("a"); - - switch (i) { - case 1: - System.out.println('1'); - break; - case 2: - System.out.println('2'); - break; - case 3: - System.out.println('3'); - break; - } - } - - System.out.println("end"); - } - - public static void whileSwitchDefault() { - System.out.println("start"); - - int i = 0; - - while (i++ < 10) { - System.out.println("a"); - - switch (i) { - case 1: - System.out.println('1'); - break; - case 2: - System.out.println('2'); - break; - case 3: - System.out.println('3'); - break; - default: - System.out.println("default"); - break; - } - } - - System.out.println("end"); - } - - public static void whileTryFinally(int i) { - System.out.println("start"); - - while (i < 5) { - try { - System.out.println("a"); - } finally { - i++; - } - } - - System.out.println("end"); - } - - public static void tryWhileFinally(int i) { - System.out.println("start"); - - try { - while (i < 5) { - System.out.println("a"); - i++; - } - } finally { - System.out.println("b"); - } - - System.out.println("end"); - } - - public static void infiniteWhileTryFinally(int i) { - System.out.println("start"); - - while (true) { - try { - System.out.println("a"); - } finally { - i++; - } - } - } - - public static void tryInfiniteWhileFinally(int i) { - System.out.println("start"); - - try { - while (true) { - System.out.println("a"); - } - } finally { - System.out.println("b"); - } - } + public void whileTryThrow(int i0) throws Exception { + int $i1 = 1; + + if ($i1 == 2) + throw new Exception("2"); + + while (i0 > 20) + { + try + { + $i1 = i0; + i0 = i0 -1; + System.out.println($i1); + + if ($i1 == 3) + throw new Exception("3"); + } + catch (RuntimeException $r3) + { + System.out.println("RuntimeException caught: " + $r3); + } + } + + return; + } + + public void loop3() { + int i = 0; + + while (i<5) + { + System.out.println(i); + ++i; + } + } + + public void whileThrow() { + System.out.println("a"); + int i = 0; + + while (i < 10) + { + System.out.println("b"); + i++; + + if (i == 3) + throw new RuntimeException(); + } + + System.out.println("c"); + } + + public void whileReturn() { + System.out.println("a"); + int i = 0; + + while (i < 10) + { + System.out.println("b"); + i++; + + if (i == 3) + return; + } + + System.out.println("c"); + } + + public void whileIfContinue() { + System.out.println("a"); + int i = 0; + + while (i > 0) + { + System.out.println("b"); + i++; + if (i > 5) + continue; + System.out.println("bb"); + } + System.out.println("c"); + } + + public void whileIfBreak() { + System.out.println("a"); + int i = 0; + + while (i > 0) + { + System.out.println("b"); + i++; + if (i > 8) + break; + System.out.println("bb"); + } + System.out.println("c"); + } + + public void whileIfContinueBreak() { + System.out.println("a"); + int i = 0; + + while (i > 0) + { + System.out.println("b"); + i++; + if (i > 5) + continue; + if (i > 8) + break; + if (i > 10) + break; + System.out.println("bb"); + } + System.out.println("c"); + } + + public void whileTrue() { + System.out.println("a"); + int i = 0; + + while (true) + { + System.out.println("b"); + i++; + if (i > 5) + continue; + if (i > 8) + break; + if (i > 10) + break; + System.out.println("bb"); + } + + System.out.println("c"); + } + + public void whileTrueIf() { + int i=0; + + System.out.println("a"); + + while (true) + { + System.out.println("b"); + if (i == 4) + { + for (int j=0; j<10; j++) + System.out.println("c"); + break; + } + else if (i == 5) + { + System.out.println("d"); + continue; + } + else if (i == 6) + { + System.out.println("e"); + break; + } + System.out.println("f"); + i++; + } + + System.out.println("g"); + + switch (i) + { + case 1: + System.out.println("h"); + case 2: + System.out.println("i"); + break; + case 3: + System.out.println("j"); + } + + System.out.println("k"); + } + + private void whileWhile() { + int a = 2; + int b = 2; + + while (a>0) { + while (b>0) { + a--; + b--; + } + } + } + + private static void whileTestPreInc() { + int i = 0; + + while (++i < 10) + { + System.out.println("1"); + } + } + + private static void whilePreInc() { + int i = 0; + + while (i < 10) + { + System.out.println("2"); + ++i; + } + } + + private static void whileTestPostInc() { + int i = 0; + + while (i++ < 10) + { + System.out.println("1"); + } + } + + private static void whilePostInc() { + int i = 0; + + while (i < 10) + { + System.out.println("2"); + i++; + } + } + + public void whileANDCondition(int i) { + System.out.println("start"); + + while ((i==4) && (i==5) && (i==6)) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public void whileORAndANDConditions(int i) { + System.out.println("start"); + + while ((i==1 || (i==5 && i==6 && i==7) || i==8 || (i==9 && i==10 && i==11)) && (i==4 || (i%200) > 50) && (i>3 || i>4)) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public void whileAndANDConditions(int i) + { + System.out.println("start"); + + while ((i==1 && (i==5 || i==6 || i==7) && i==8 && (i==9 || i==10 || i==11)) || (i==4 && (i%200) > 50) || (i>3 && i>4)) { + System.out.println("a"); + } + + System.out.println("end"); + } + + public static int whileContinueBreak(int[] array) { + int i = 0; + int length = array.length; + int counter = 0; + + while (i < length) { + int item = array[i]; + + if (item % 2 == 1) { + counter++; + continue; + } + + i++; + break; + } + + i++; + + return counter; + } + + public static void twoWiles() { + int i = 0; + + while (i < 5) { + i++; + } + + while (i < 10) { + i++; + } + + i++; + } + + public static void whileSwitch() { + System.out.println("start"); + + int i = 0; + + while (i++ < 10) { + System.out.println("a"); + + switch (i) { + case 1: + System.out.println('1'); + break; + case 2: + System.out.println('2'); + break; + case 3: + System.out.println('3'); + break; + } + } + + System.out.println("end"); + } + + public static void whileSwitchDefault() { + System.out.println("start"); + + int i = 0; + + while (i++ < 10) { + System.out.println("a"); + + switch (i) { + case 1: + System.out.println('1'); + break; + case 2: + System.out.println('2'); + break; + case 3: + System.out.println('3'); + break; + default: + System.out.println("default"); + break; + } + } + + System.out.println("end"); + } + + public static void whileTryFinally(int i) { + System.out.println("start"); + + while (i < 5) { + try { + System.out.println("a"); + } finally { + i++; + } + } + + System.out.println("end"); + } + + public static void tryWhileFinally(int i) { + System.out.println("start"); + + try { + while (i < 5) { + System.out.println("a"); + i++; + } + } finally { + System.out.println("b"); + } + + System.out.println("end"); + } + + public static void infiniteWhileTryFinally(int i) { + System.out.println("start"); + + while (true) { + try { + System.out.println("a"); + } finally { + i++; + } + } + } + + public static void tryInfiniteWhileFinally(int i) { + System.out.println("start"); + + try { + while (true) { + System.out.println("a"); + } + } finally { + System.out.println("b"); + } + } } From 7d8a365cde313f5ab874b585143173cad00c488a Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 21 Jul 2019 18:12:14 +0200 Subject: [PATCH 044/211] Fix indentation --- src/main/java/org/jd/core/v1/api/Decompiler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jd/core/v1/api/Decompiler.java b/src/main/java/org/jd/core/v1/api/Decompiler.java index 260f5fe0..98fa3a40 100644 --- a/src/main/java/org/jd/core/v1/api/Decompiler.java +++ b/src/main/java/org/jd/core/v1/api/Decompiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -13,7 +13,7 @@ import java.util.Map; public interface Decompiler { - void decompile(Loader loader, Printer printer, String internalName) throws Exception; + void decompile(Loader loader, Printer printer, String internalName) throws Exception; - void decompile(Loader loader, Printer printer, String internalName, Map configuration) throws Exception; + void decompile(Loader loader, Printer printer, String internalName, Map configuration) throws Exception; } From 1dd36f94df7622b4c5855bff27a63884c51b1e3b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 21 Jul 2019 19:17:28 +0200 Subject: [PATCH 045/211] Fix bug on method declarations --- .../util/SignatureParser.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java index 62685376..7f9d0be6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -124,6 +124,7 @@ public MethodTypes parseConstructorSignature(Method method) { if (attributeSignature == null) { return parseMethodSignature(method.getDescriptor(), method); } else { + // Signature does not contain synthetic parameters like outer type name, for example. MethodTypes mt1 = parseMethodSignature(attributeSignature.getSignature(), method); MethodTypes mt2 = parseMethodSignature(method.getDescriptor(), method); @@ -201,7 +202,17 @@ public static int countDimension(String descriptor) { */ @SuppressWarnings("unchecked") protected MethodTypes parseMethodSignature(String signature, Method method) { - MethodTypes methodTypes = methodTypesCache.get(signature); + String cacheKey = signature; + + if (method != null) { + AttributeExceptions attributeExceptions = method.getAttribute("Exceptions"); + + if (attributeExceptions != null) { + cacheKey += attributeExceptions.getExceptionTypeNames().hashCode(); + } + } + + MethodTypes methodTypes = methodTypesCache.get(cacheKey); if (methodTypes == null) { SignatureReader reader = new SignatureReader(signature); From 1882ab43bb166eb91f93dc49e483f72b2af6bdd8 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 21 Jul 2019 20:09:37 +0200 Subject: [PATCH 046/211] Fix bug on method declarations --- .../classfiletojavasyntax/util/SignatureParser.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java index 7f9d0be6..8dbfb904 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java @@ -203,12 +203,19 @@ public static int countDimension(String descriptor) { @SuppressWarnings("unchecked") protected MethodTypes parseMethodSignature(String signature, Method method) { String cacheKey = signature; + boolean containsThrowsSignature = (signature.indexOf('^') != -1); - if (method != null) { + if (!containsThrowsSignature && (method != null)) { AttributeExceptions attributeExceptions = method.getAttribute("Exceptions"); if (attributeExceptions != null) { - cacheKey += attributeExceptions.getExceptionTypeNames().hashCode(); + StringBuilder sb = new StringBuilder(signature); + + for (String exceptionTypeName : attributeExceptions.getExceptionTypeNames()) { + sb.append("^L").append(exceptionTypeName).append(';'); + } + + cacheKey = sb.toString(); } } @@ -297,7 +304,7 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { } } - methodTypesCache.put(signature, methodTypes); + methodTypesCache.put(cacheKey, methodTypes); } return methodTypes; From 41262a9ab754cd79a8ed72d2ad0a311c84b666c6 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 24 Jul 2019 08:04:24 +0200 Subject: [PATCH 047/211] Fix bug on empty switch statement --- .../classfiletojavasyntax/util/ByteCodeParser.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 79bfc349..ee798435 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -272,7 +272,11 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, TYPE_SHORT, new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); break; case 87: case 88: // POP, POP2 - statements.add(new ExpressionStatement(stack.pop())); + expression1 = stack.pop(); + Class clazz = expression1.getClass(); + if ((clazz != ClassFileLocalVariableReferenceExpression.class) && (clazz != FieldReferenceExpression.class)) { + statements.add(new ExpressionStatement(expression1)); + } break; case 89: // DUP : ..., value => ..., value, value expression1 = stack.pop(); From 5ae9e8ac4506a91a8160c92bf563ff4e4db9d4f7 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 24 Jul 2019 08:20:19 +0200 Subject: [PATCH 048/211] Add type arguments on variable declaration of type 'Class' --- .../TypeReferenceDotClassExpression.java | 7 +++++-- .../localvariable/ObjectLocalVariable.java | 4 ++-- .../JavaSyntaxToJavaFragmentProcessor.java | 5 +++-- .../visitor/CompilationUnitVisitor.java | 6 +++--- .../visitor/ExpressionVisitor.java | 4 ++-- .../visitor/StatementVisitor.java | 6 +++--- .../visitor/TypeVisitor.java | 19 ++++++++++++++++--- 7 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java index 2500b76c..17168519 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TypeReferenceDotClassExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -13,14 +13,17 @@ public class TypeReferenceDotClassExpression implements Expression { protected int lineNumber; protected Type typeDotClass; + protected Type type; public TypeReferenceDotClassExpression(Type typeDotClass) { this.typeDotClass = typeDotClass; + this.type = ObjectType.TYPE_CLASS.createType(typeDotClass); } public TypeReferenceDotClassExpression(int lineNumber, Type typeDotClass) { this.lineNumber = lineNumber; this.typeDotClass = typeDotClass; + this.type = ObjectType.TYPE_CLASS.createType(typeDotClass); } @Override @@ -34,7 +37,7 @@ public Type getTypeDotClass() { @Override public Type getType() { - return ObjectType.TYPE_CLASS; + return type; } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index dcec509d..a762dd81 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -156,7 +156,7 @@ public void leftReduce(Type otherType) { } else if ((dimension == 0) && (otherType.getDimension() == 0) && otherType.isObject()) { ObjectType otherObjectType = (ObjectType) otherType; - if (!toType.getInternalName().equals(otherObjectType.getInternalName()) && objectTypeMaker.isAssignable(otherObjectType, toType)) { + if (toType.getInternalName().equals(otherObjectType.getInternalName()) || objectTypeMaker.isAssignable(otherObjectType, toType)) { if (toType.getTypeArguments() == null) { toType = otherObjectType; } else if (otherObjectType.getTypeArguments() == null) { diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java index f78fd20a..d01297f7 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -26,6 +26,7 @@ public class JavaSyntaxToJavaFragmentProcessor implements Processor { public void process(Message message) throws Exception { Loader loader = message.getHeader("loader"); String mainInternalTypeName = message.getHeader("mainInternalTypeName"); + int majorVersion = message.getHeader("majorVersion"); CompilationUnit compilationUnit = message.getBody(); SearchImportsVisitor importsVisitor = new SearchImportsVisitor(mainInternalTypeName); @@ -33,7 +34,7 @@ public void process(Message message) throws Exception { ImportsFragment importsFragment = importsVisitor.getImportsFragment(); message.setHeader("maxLineNumber", importsVisitor.getMaxLineNumber()); - CompilationUnitVisitor visitor = new CompilationUnitVisitor(loader, mainInternalTypeName, importsFragment); + CompilationUnitVisitor visitor = new CompilationUnitVisitor(loader, mainInternalTypeName, majorVersion, importsFragment); visitor.visit(compilationUnit); message.setBody(visitor.getFragments()); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 488322b2..25d33e69 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -49,8 +49,8 @@ public class CompilationUnitVisitor extends StatementVisitor { protected SingleLineStatementVisitor singleLineStatementVisitor = new SingleLineStatementVisitor(); protected String mainInternalName; - public CompilationUnitVisitor(Loader loader, String mainInternalTypeName, ImportsFragment importsFragment) { - super(loader, mainInternalTypeName, importsFragment); + public CompilationUnitVisitor(Loader loader, String mainInternalTypeName, int majorVersion, ImportsFragment importsFragment) { + super(loader, mainInternalTypeName, majorVersion, importsFragment); this.mainInternalName = mainInternalTypeName; } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index cf97a0ab..72da9546 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -54,8 +54,8 @@ public class ExpressionVisitor extends TypeVisitor { protected String currentTypeName; protected HexaExpressionVisitor hexaExpressionVisitor = new HexaExpressionVisitor(); - public ExpressionVisitor(Loader loader, String mainInternalTypeName, ImportsFragment importsFragment) { - super(loader, mainInternalTypeName, importsFragment); + public ExpressionVisitor(Loader loader, String mainInternalTypeName, int majorVersion, ImportsFragment importsFragment) { + super(loader, mainInternalTypeName, majorVersion, importsFragment); } public DefaultList getFragments() { diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java index 0fab16c7..ac0a7f3b 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -43,8 +43,8 @@ public class StatementVisitor extends ExpressionVisitor { public static final KeywordToken TRY = new KeywordToken("try"); public static final KeywordToken WHILE = new KeywordToken("while"); - public StatementVisitor(Loader loader, String mainInternalTypeName, ImportsFragment importsFragment) { - super(loader, mainInternalTypeName, importsFragment); + public StatementVisitor(Loader loader, String mainInternalTypeName, int majorVersion, ImportsFragment importsFragment) { + super(loader, mainInternalTypeName, majorVersion, importsFragment); } @Override diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index 880e2b3c..f32b293a 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; public class TypeVisitor extends AbstractJavaSyntaxVisitor { @@ -50,14 +51,16 @@ public class TypeVisitor extends AbstractJavaSyntaxVisitor { protected Loader loader; protected String internalPackageName; + protected int majorVersion; protected ImportsFragment importsFragment; protected Tokens tokens; protected int maxLineNumber = 0; protected String currentInternalTypeName; protected HashMap textTokenCache = new HashMap<>(); - public TypeVisitor(Loader loader, String mainInternalTypeName, ImportsFragment importsFragment) { + public TypeVisitor(Loader loader, String mainInternalTypeName, int majorVersion, ImportsFragment importsFragment) { this.loader = loader; + this.majorVersion = majorVersion; this.importsFragment = importsFragment; int index = mainInternalTypeName.lastIndexOf('/'); @@ -104,7 +107,17 @@ public void visit(ObjectType type) { tokens.add(newTypeReferenceToken(type, currentInternalTypeName)); // Build token for type arguments - visitTypeArgumentList(type.getTypeArguments()); + BaseTypeArgument typeArguments = type.getTypeArguments(); + + if (majorVersion >= 49) { // (majorVersion >= Java 5) + if (typeArguments != null) { + visitTypeArgumentList(typeArguments); + } else if (type.equals(TYPE_CLASS)) { + tokens.add(TextToken.LEFTANGLEBRACKET); + tokens.add(TextToken.QUESTIONMARK); + tokens.add(TextToken.RIGHTANGLEBRACKET); + } + } // Build token for dimension visitDimension(type.getDimension()); From 87ecfad3f97fff162925366cbe845a996b41bedf Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 29 Jul 2019 10:18:23 +0200 Subject: [PATCH 049/211] Fix bugs on local variable declaration --- .../declaration/ClassFileFormalParameter.java | 73 +++++++++++++++++++ ...sFileLocalVariableReferenceExpression.java | 7 +- .../localvariable/AbstractLocalVariable.java | 13 ++-- .../model/localvariable/Frame.java | 29 +++++++- .../model/localvariable/LocalVariable.java | 5 +- .../localvariable/LocalVariableReference.java | 15 ++++ .../model/localvariable/LocalVariableSet.java | 19 ++++- .../localvariable/ObjectLocalVariable.java | 10 +++ .../localvariable/PrimitiveLocalVariable.java | 5 ++ .../util/ByteCodeParser.java | 70 +++++++++++++----- .../util/LocalVariableMaker.java | 39 ++++++---- .../visitor/InitInnerClassVisitor.java | 8 +- ...RemoveBinaryOpReturnStatementsVisitor.java | 4 +- .../UpdateIntegerConstantTypeVisitor.java | 3 +- 14 files changed, 245 insertions(+), 55 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFormalParameter.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableReference.java diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFormalParameter.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFormalParameter.java new file mode 100644 index 00000000..ccab6a00 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFormalParameter.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.declaration.FormalParameter; +import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.LocalVariableReference; + + +public class ClassFileFormalParameter extends FormalParameter implements LocalVariableReference { + protected AbstractLocalVariable localVariable; + + public ClassFileFormalParameter(AbstractLocalVariable localVariable) { + super(null, null); + this.localVariable = localVariable; + } + + public ClassFileFormalParameter(AbstractLocalVariable localVariable, boolean varargs) { + super(null, varargs, null); + this.localVariable = localVariable; + } + + public ClassFileFormalParameter(BaseAnnotationReference annotationReferences, AbstractLocalVariable localVariable, boolean varargs) { + super(annotationReferences, null, varargs, null); + this.localVariable = localVariable; + } + + public Type getType() { + return localVariable.getType(); + } + + public String getName() { + return localVariable.getName(); + } + + public void setName(String name) { + localVariable.setName(name); + } + + @Override + public AbstractLocalVariable getLocalVariable() { + return localVariable; + } + + @Override + public void setLocalVariable(AbstractLocalVariable localVariable) { + this.localVariable = localVariable; + } + + @Override + public String toString() { + String s = "ClassFileFormalParameter{"; + + if (annotationReferences != null) + s += annotationReferences + " "; + + Type type = localVariable.getType(); + + if (varargs) + s += type.createType(type.getDimension()-1) + "... "; + else + s += type + " "; + + return s + localVariable.getName() + "}"; + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java index bf0da27b..1a05ce35 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -10,8 +10,9 @@ import org.jd.core.v1.model.javasyntax.expression.LocalVariableReferenceExpression; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.LocalVariableReference; -public class ClassFileLocalVariableReferenceExpression extends LocalVariableReferenceExpression { +public class ClassFileLocalVariableReferenceExpression extends LocalVariableReferenceExpression implements LocalVariableReference { protected AbstractLocalVariable localVariable; public ClassFileLocalVariableReferenceExpression(int lineNumber, AbstractLocalVariable localVariable) { @@ -30,10 +31,12 @@ public String getName() { return localVariable.getName(); } + @Override public AbstractLocalVariable getLocalVariable() { return localVariable; } + @Override public void setLocalVariable(AbstractLocalVariable localVariable) { this.localVariable = localVariable; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java index b7a84e3b..ec4424d5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -20,7 +20,7 @@ public abstract class AbstractLocalVariable implements LocalVariable { protected int toOffset; protected String name; protected int dimension; - protected DefaultList references = new DefaultList<>(); + protected DefaultList references = new DefaultList<>(); public AbstractLocalVariable(int index, int offset, int dimension) { this.declared = (offset == 0); @@ -106,9 +106,13 @@ public void setToOffset(int offset) { @Override public String getName() { return name; } + public void setName(String name) { + this.name = name; + } + public int getDimension() { return dimension; } - public DefaultList getReferences() { + public DefaultList getReferences() { return references; } @@ -121,8 +125,7 @@ public DefaultList getReferences() { public abstract void rightReduce(Type otherType); public abstract void rightReduce(AbstractLocalVariable other); - @Override - public void addReference(ClassFileLocalVariableReferenceExpression reference) { + public void addReference(LocalVariableReference reference) { references.add(reference); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index a86eefe4..0c310215 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -98,12 +98,34 @@ public void mergeLocalVariable(AbstractLocalVariable lv) { } } } else if (lv != alvToMerge) { - for (ClassFileLocalVariableReferenceExpression reference : alvToMerge.getReferences()) { + for (LocalVariableReference reference : alvToMerge.getReferences()) { reference.setLocalVariable(lv); } lv.getReferences().addAll(alvToMerge.getReferences()); lv.setFromOffset(alvToMerge.getFromOffset()); + + if (!lv.isAssignable(alvToMerge)) { + Type type = lv.getType(); + Type alvToMergeType = alvToMerge.getType(); + + assert (type.isPrimitive() == alvToMergeType.isPrimitive()) && (type.isObject() == alvToMergeType.isObject()) && (type.isGeneric() == alvToMergeType.isGeneric()); + + if (type.isPrimitive()) { + if (alvToMerge.isAssignable(lv)) { + ((PrimitiveLocalVariable)lv).setPrimitiveType((PrimitiveType)type); + } else { + ((PrimitiveLocalVariable)lv).setPrimitiveType(PrimitiveType.TYPE_INT); + } + } else if (type.isObject()) { + if (alvToMerge.isAssignable(lv)) { + ((ObjectLocalVariable)lv).setObjectType((ObjectType)type); + } else { + ((ObjectLocalVariable)lv).setObjectType(ObjectType.TYPE_OBJECT); + } + } + } + localVariableArray[index] = alvToMerge.getNext(); } } @@ -474,8 +496,7 @@ protected void updateForStatement( } @SuppressWarnings("unchecked") - protected void updateForStatement( - HashSet variablesToDeclare, HashSet foundVariables, ClassFileForStatement forStatement, Expressions init) { + protected void updateForStatement(HashSet variablesToDeclare, HashSet foundVariables, ClassFileForStatement forStatement, Expressions init) { DefaultList boes = new DefaultList<>(); DefaultList localVariables = new DefaultList<>(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java index 51531c82..eecb5361 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,7 +8,6 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; public interface LocalVariable { @@ -16,7 +15,5 @@ public interface LocalVariable { String getName(); - void addReference(ClassFileLocalVariableReferenceExpression reference); - void accept(LocalVariableVisitor visitor); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableReference.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableReference.java new file mode 100644 index 00000000..cc141b7f --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableReference.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; + + +public interface LocalVariableReference { + AbstractLocalVariable getLocalVariable(); + + void setLocalVariable(AbstractLocalVariable localVariable); +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java index 344aeffc..93d00f2c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -95,6 +95,23 @@ public AbstractLocalVariable remove(int index, int offset) { return null; } + public AbstractLocalVariable get(int index, int offset) { + if (index < array.length) { + AbstractLocalVariable lv = array[index]; + + while (lv != null) { + if (lv.fromOffset <= offset) { + return lv; + } + + assert lv != lv.getNext(); + lv = lv.getNext(); + } + } + + return null; + } + public boolean isEmpty() { return size == 0; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index a762dd81..188a571a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -76,6 +76,16 @@ public Type getType() { return (dimension == 0) ? toType : arrayType; } + public void setObjectType(ObjectType type) { + dimension = type.getDimension(); + + if (dimension == 0) { + this.fromType = this.toType = (ObjectType)type; + } else { + this.arrayType = type; + } + } + @Override public boolean isAssignable(AbstractLocalVariable other) { if (other.getClass() == ObjectLocalVariable.class) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java index 525308f9..ec682a67 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java @@ -57,6 +57,11 @@ public Type getType() { return PrimitiveTypeUtil.getPrimitiveType(flags, dimension); } + public void setPrimitiveType(PrimitiveType type) { + assert type.getDimension() == 0; + this.flags = type.getFlags(); + } + @Override public boolean isAssignable(AbstractLocalVariable other) { if ((other.getDimension() == 0) && (other.getClass() == PrimitiveLocalVariable.class)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index ee798435..ce821203 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -658,25 +658,25 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 161: // IF_ICMPLT expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">=" : "<", expression2, 8)); + stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">=" : "<", expression2, 8)); offset += 2; // Skip branch offset break; case 162: // IF_ICMPGE expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<" : ">=", expression2, 8)); + stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<" : ">=", expression2, 8)); offset += 2; // Skip branch offset break; case 163: // IF_ICMPGT expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<=" : ">", expression2, 8)); + stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<=" : ">", expression2, 8)); offset += 2; // Skip branch offset break; case 164: // IF_ICMPLE expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">" : "<=", expression2, 8)); + stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">" : "<=", expression2, 8)); offset += 2; // Skip branch offset break; case 168: // JSR @@ -736,19 +736,19 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau BaseExpression parameters = getParameters(statements, stack, descriptor); Type returnedType = signatureParser.parseReturnedType(descriptor); - if (!statements.isEmpty() && (opcode == 184)) { // INVOKESTATIC - Statement last = statements.getLast(); - - if (last.getClass() == ExpressionStatement.class) { - Expression expression = ((ExpressionStatement)last).getExpression(); - - if ((expression.getLineNumber() == lineNumber) && (expression.getType().equals(ot))) { - statements.removeLast(); - stack.push(expression); - opcode = 0; - } - } - } +// if (!statements.isEmpty() && (opcode == 184)) { // INVOKESTATIC +// Statement last = statements.getLast(); +// +// if (last.getClass() == ExpressionStatement.class) { +// Expression expression = ((ExpressionStatement)last).getExpression(); +// +// if ((expression.getLineNumber() == lineNumber) && (expression.getType().equals(ot))) { +// statements.removeLast(); +// stack.push(expression); +// opcode = 0; +// } +// } +// } if (opcode == 184) { // INVOKESTATIC expression1 = new MethodInvocationExpression(lineNumber, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameters); @@ -1797,6 +1797,42 @@ private static Expression newComparisonOperatorExpression(int lineNumber, Expres return new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, leftExpression, operator, rightExpression, priority); } + private static Expression newNumericComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + Type leftType = leftExpression.getType(); + Type rightType = rightExpression.getType(); + Type type; + + if (leftType == rightType) { + type = leftType; + } else { + type = PrimitiveTypeUtil.getCommonPrimitiveType((PrimitiveType)leftType, (PrimitiveType)rightType); + if (type == null) { + type = leftType; + } + } + + if ((((PrimitiveType)type).getFlags() & (FLAG_CHAR|FLAG_BYTE|FLAG_SHORT|FLAG_INT)) != 0) { + if (leftExpression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + ClassFileLocalVariableReferenceExpression lvre = (ClassFileLocalVariableReferenceExpression) leftExpression; + + if (lvre.getLocalVariable().getClass() == PrimitiveLocalVariable.class) { + PrimitiveLocalVariable plv = (PrimitiveLocalVariable) lvre.getLocalVariable(); + plv.leftReduce(type); + } + } + if (rightExpression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + ClassFileLocalVariableReferenceExpression lvre = (ClassFileLocalVariableReferenceExpression) rightExpression; + + if (lvre.getLocalVariable().getClass() == PrimitiveLocalVariable.class) { + PrimitiveLocalVariable plv = (PrimitiveLocalVariable) lvre.getLocalVariable(); + plv.leftReduce(type); + } + } + } + + return new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, leftExpression, operator, rightExpression, priority); + } + private static Expression newPreArithmeticOperatorExpression(int lineNumber, String operator, Expression expression) { reduceIntegerLocalVariableType(expression); return new PreOperatorExpression(lineNumber, operator, expression); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 641d0fd9..c4c9c2f2 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -22,6 +22,7 @@ import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFormalParameter; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.*; @@ -143,7 +144,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa for (int parameterIndex=0, variableIndex=firstVariableIndex; parameterIndex<=lastParameterIndex; parameterIndex++, variableIndex++) { AbstractLocalVariable lv = localVariableSet.root(variableIndex); - formalParameters.add(new FormalParameter(lv.getType(), varargs && (parameterIndex==lastParameterIndex), lv.getName())); + formalParameters.add(new ClassFileFormalParameter(lv, varargs && (parameterIndex==lastParameterIndex))); if (PrimitiveType.TYPE_LONG.equals(lv.getType()) || PrimitiveType.TYPE_DOUBLE.equals(lv.getType())) { variableIndex++; @@ -161,7 +162,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa Annotations invisibles = ((invisiblesArray == null) || (invisiblesArray.length <= parameterIndex)) ? null : invisiblesArray[parameterIndex]; BaseAnnotationReference annotationReferences = annotationConverter.convert(visibles, invisibles); - formalParameters.add(new FormalParameter(annotationReferences, lv.getType(), varargs && (parameterIndex==lastParameterIndex), lv.getName())); + formalParameters.add(new ClassFileFormalParameter(annotationReferences, lv, varargs && (parameterIndex==lastParameterIndex))); if (PrimitiveType.TYPE_LONG.equals(lv.getType()) || PrimitiveType.TYPE_DOUBLE.equals(lv.getType())) { variableIndex++; @@ -327,10 +328,18 @@ public AbstractLocalVariable getLocalVariable(int index, int offset) { } public AbstractLocalVariable getPrimitiveLocalVariableInAssignment(int index, int offset, Expression value) { - AbstractLocalVariable lv = localVariableSet.remove(index, offset); + AbstractLocalVariable lv = localVariableSet.get(index, offset); if (lv == null) { lv = currentFrame.getLocalVariable(index); + } else { + AbstractLocalVariable lv2 = currentFrame.getLocalVariable(index); + + if ((lv2 != null) && (lv.getFromOffset() < lv2.getFromOffset())) { + lv = lv2; + } else { + localVariableSet.remove(index, offset); + } } if (lv == null) { @@ -379,11 +388,19 @@ public AbstractLocalVariable getPrimitiveLocalVariableInAssignment(int index, in } public AbstractLocalVariable getObjectLocalVariableInAssignment(int index, int offset, Expression value) { - AbstractLocalVariable lv = localVariableSet.remove(index, offset); + AbstractLocalVariable lv = localVariableSet.get(index, offset); Class valueClass = value.getClass(); if (lv == null) { lv = currentFrame.getLocalVariable(index); + } else { + AbstractLocalVariable lv2 = currentFrame.getLocalVariable(index); + + if ((lv2 != null) && (lv.getFromOffset() < lv2.getFromOffset())) { + lv = lv2; + } else { + localVariableSet.remove(index, offset); + } } if (lv == null) { @@ -453,21 +470,15 @@ public AbstractLocalVariable getExceptionLocalVariable(int index, int offset, Ob if (index == -1) { currentFrame.setExceptionLocalVariable(lv = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null, true)); } else { - lv = currentFrame.getLocalVariable(index); + lv = localVariableSet.remove(index, offset); if (lv == null) { - lv = localVariableSet.remove(index, offset); - - if (lv == null) { - lv = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null, true); - } else { - lv.setDeclared(true); - } - - currentFrame.addLocalVariable(lv); + lv = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null, true); } else { lv.setDeclared(true); } + + currentFrame.addLocalVariable(lv); } return lv; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 0277dd60..7d2b3bdb 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -134,7 +134,7 @@ public void visit(ConstructorDeclaration declaration) { int size = list.size(); list.subList(size - count, size).clear(); } - } else { + } else if (outerType != null) { cfcd.setFormalParameters(null); } } @@ -510,10 +510,8 @@ public void visit(LocalVariableDeclaration declaration) { @Override public void visit(LocalVariableDeclarator declarator) { if (finalLocalVariableNameMap.containsKey(declarator.getName())) { - LocalVariableDeclarator cflvd = (LocalVariableDeclarator)declarator; - fina1 = true; - cflvd.setName(finalLocalVariableNameMap.get(declarator.getName())); + declarator.setName(finalLocalVariableNameMap.get(declarator.getName())); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java index 23700f96..d4a6c898 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -50,7 +50,7 @@ public void visit(Statements statements) { if (leftExpression.getClass() == ClassFileLocalVariableReferenceExpression.class) { ClassFileLocalVariableReferenceExpression lvr2 = (ClassFileLocalVariableReferenceExpression)leftExpression; - if (lvr1.getLocalVariable() == lvr2.getLocalVariable()) { + if ((lvr1.getLocalVariable() == lvr2.getLocalVariable()) && (lvr1.getLocalVariable().getReferences().size() == 2)) { // Remove synthetic assignment statement statements.remove(statements.size()-2); // Replace synthetic local variable with expression diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 075f115a..767590ca 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -333,6 +333,7 @@ protected BaseExpression updateExpressions(List types, BaseExpression expr case FLAG_BYTE: case FLAG_SHORT: expressions = new CastExpression(type, updatedParameter); + break; } } } From 518515c8d7fc7b4e9aab79c1215ed3eef0ff5f9b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 29 Jul 2019 10:28:23 +0200 Subject: [PATCH 050/211] In unit tests, check that the decompiled source code can be recompiled. --- .../jd/core/v1/ClassFileToJavaSourceTest.java | 1705 +++++++++-------- .../org/jd/core/v1/ControlFlowGraphTest.java | 4 +- .../jd/core/v1/JavaFragmentToTokenTest.java | 4 +- .../core/v1/LayoutFragmentProcessorTest.java | 4 +- .../ControlFlowGraphPlantUMLWriter.java | 5 +- .../org/jd/core/v1/compiler/CompilerUtil.java | 44 + .../v1/compiler/JavaSourceFileObject.java | 34 + .../jd/core/v1/printer/PlainTextPrinter.java | 12 +- .../core/v1/{util => regex}/PatternMaker.java | 4 +- 9 files changed, 1034 insertions(+), 782 deletions(-) rename src/test/java/org/jd/core/v1/{util => cfg}/ControlFlowGraphPlantUMLWriter.java (99%) create mode 100644 src/test/java/org/jd/core/v1/compiler/CompilerUtil.java create mode 100644 src/test/java/org/jd/core/v1/compiler/JavaSourceFileObject.java rename src/test/java/org/jd/core/v1/{util => regex}/PatternMaker.java (94%) diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index eb2b5a48..319b0f2e 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -9,6 +9,8 @@ import junit.framework.TestCase; import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; import org.jd.core.v1.loader.ZipLoader; import org.jd.core.v1.model.message.Message; import org.jd.core.v1.printer.PlainTextPrinter; @@ -18,7 +20,7 @@ import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; import org.jd.core.v1.service.writer.WriteTokenProcessor; -import org.jd.core.v1.util.PatternMaker; +import org.jd.core.v1.regex.PatternMaker; import org.junit.Test; import java.io.InputStream; @@ -26,6 +28,7 @@ import java.util.HashMap; import java.util.Map; + public class ClassFileToJavaSourceTest extends TestCase { protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); @@ -37,6 +40,7 @@ public class ClassFileToJavaSourceTest extends TestCase { @Test public void testJdk170Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -44,7 +48,7 @@ public void testJdk170Basic() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -60,75 +64,77 @@ public void testJdk170Basic() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("serialVersionUID = 9506606333927794L;") != -1); assertTrue(source.indexOf(".indexOf('B');") != -1); - assertTrue(source.matches(PatternMaker.make("[ 26: 26]", "System.out.println(\"hello\");"))); + assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "System.out.println(\"hello\");"))); assertTrue(source.indexOf("String str1 = \"3 == \" + (i + 1) + \" ?\";") != -1); - assertTrue(source.indexOf("String str2 = str1.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); + assertTrue(source.indexOf("String str2 = String.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); assertTrue(source.indexOf("char c2 = '€';") != -1); assertTrue(source.indexOf("char c3 = '\\'';") != -1); assertTrue(source.indexOf("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');") != -1); - assertTrue(source.indexOf("Class class3 = String.class, class2 = class3, class1 = class2;") != -1); - assertTrue(source.matches(PatternMaker.make("Class class5 = doSomething(class6 = String.class, args1 = args2 = new String[], class4 = class5;"))); + assertTrue(source.indexOf("Class class3 = String.class, class2 = class3, class1 = class2;") != -1); + assertTrue(source.matches(PatternMaker.make("Class class5 = doSomething(class6 = String.class, args1 = args2 = new String[], class4 = class5;"))); assertTrue(source.matches(PatternMaker.make("int j = 1, k[] = {1, l[][] = {"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); - assertTrue(source.matches(PatternMaker.make(": 58]", "return new String[] {s, s + '?'};"))); + assertTrue(source.matches(PatternMaker.make(": 58 */", "return new String[] {s, s + '?'};"))); assertTrue(source.indexOf("if (this instanceof Object)") != -1); assertTrue(source.indexOf("int k = 50 / (25 + (i = 789));") != -1); - assertTrue(source.matches(PatternMaker.make(": 80]", "k = i += 100;"))); - assertTrue(source.matches(PatternMaker.make(": 85]", "i = ++this.int78;"))); - assertTrue(source.matches(PatternMaker.make(": 86]", "i = this.int78++;"))); - assertTrue(source.matches(PatternMaker.make(": 87]", "i *= 10;"))); - assertTrue(source.matches(PatternMaker.make(": 89]", "this.int78 = ++i;"))); - assertTrue(source.matches(PatternMaker.make(": 90]", "this.int78 = i++;"))); - assertTrue(source.matches(PatternMaker.make(": 91]", "this.int78 *= 10;"))); - assertTrue(source.matches(PatternMaker.make(": 93]", "long34 = ++long12;"))); - assertTrue(source.matches(PatternMaker.make(": 94]", "long34 = long12++;"))); - assertTrue(source.matches(PatternMaker.make(": 95]", "long34 *= 10L;"))); - assertTrue(source.matches(PatternMaker.make(": 97]", "i = (int)long12 + this.int78;"))); - assertTrue(source.matches(PatternMaker.make(": 99]", "i = k ^ 0xFF;"))); - assertTrue(source.matches(PatternMaker.make(": 100]", "i |= 0x7;"))); + assertTrue(source.matches(PatternMaker.make(": 80 */", "k = i += 100;"))); + assertTrue(source.matches(PatternMaker.make(": 85 */", "i = ++this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 86 */", "i = this.int78++;"))); + assertTrue(source.matches(PatternMaker.make(": 87 */", "i *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 89 */", "this.int78 = ++i;"))); + assertTrue(source.matches(PatternMaker.make(": 90 */", "this.int78 = i++;"))); + assertTrue(source.matches(PatternMaker.make(": 91 */", "this.int78 *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 93 */", "long34 = ++long12;"))); + assertTrue(source.matches(PatternMaker.make(": 94 */", "long34 = long12++;"))); + assertTrue(source.matches(PatternMaker.make(": 95 */", "long34 *= 10L;"))); + assertTrue(source.matches(PatternMaker.make(": 97 */", "i = (int)long12 + this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 99 */", "i = k ^ 0xFF;"))); + assertTrue(source.matches(PatternMaker.make(": 100 */", "i |= 0x7;"))); assertTrue(source.indexOf("int result;") != -1); - assertTrue(source.matches(PatternMaker.make(": 112]", "result = 1;"))); - assertTrue(source.matches(PatternMaker.make(": 114]", "int k = i;"))); - assertTrue(source.matches(PatternMaker.make(": 115]", "result = k + 2;"))); - assertTrue(source.matches(PatternMaker.make(": 118]", "result = this.short56;"))); - assertTrue(source.matches(PatternMaker.make(": 122]", "return result;"))); - assertTrue(source.matches(PatternMaker.make(": 126]", "int int78 = getInt78(new Object[] { this }, (short)5);"))); - assertTrue(source.matches(PatternMaker.make(": 128]", "i = (int)(Basic.long12 + long12) + this.int78 + int78;"))); + assertTrue(source.matches(PatternMaker.make(": 112 */", "result = 1;"))); + assertTrue(source.matches(PatternMaker.make(": 114 */", "int k = i;"))); + assertTrue(source.matches(PatternMaker.make(": 115 */", "result = k + 2;"))); + assertTrue(source.matches(PatternMaker.make(": 118 */", "result = this.short56;"))); + assertTrue(source.matches(PatternMaker.make(": 122 */", "return result;"))); + assertTrue(source.matches(PatternMaker.make(": 126 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make(": 128 */", "i = (int)(Basic.long12 + long12) + this.int78 + int78;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("()") == -1); - assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170NoDebugBasic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -143,16 +149,17 @@ public void testJdk170NoDebugBasic() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.matches(PatternMaker.make("System.out.println(\"hello\");"))); assertTrue(source.matches(PatternMaker.make("String str1 = \"3 == \" + (paramInt + 1) + \" ?\";"))); - assertTrue(source.indexOf("String str2 = str1.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); + assertTrue(source.indexOf("String str2 = String.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); assertTrue(source.matches(PatternMaker.make("char c2 = '€';"))); assertTrue(source.matches(PatternMaker.make("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');"))); - assertTrue(source.matches(PatternMaker.make("Class clazz3 = String.class;"))); - assertTrue(source.matches(PatternMaker.make("Class clazz2 = clazz3;"))); - assertTrue(source.matches(PatternMaker.make("Class clazz1 = clazz2;"))); - assertTrue(source.indexOf("Class clazz5 = doSomething(clazz6 = String.class, arrayOfString1 = arrayOfString2 = new String[]") != -1); + assertTrue(source.matches(PatternMaker.make("Class clazz3 = String.class;"))); + assertTrue(source.matches(PatternMaker.make("Class clazz2 = clazz3;"))); + assertTrue(source.matches(PatternMaker.make("Class clazz1 = clazz2;"))); + assertTrue(source.indexOf("Class clazz5 = doSomething(clazz6 = String.class, arrayOfString1 = arrayOfString2 = new String[]") != -1); assertTrue(source.matches(PatternMaker.make("if (this instanceof Object)"))); @@ -161,22 +168,23 @@ public void testJdk170NoDebugBasic() throws Exception { assertTrue(source.indexOf("protected static final Integer INTEGER_255 = new Integer(255);") != -1); assertTrue(source.indexOf("()") == -1); - assertTrue(source.indexOf("null = ") == -1); assertTrue(source.indexOf("NaND") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170Constructors() throws Exception { + String internalClassName = "org/jd/core/test/Constructors"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Constructors"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -191,22 +199,25 @@ public void testJdk170Constructors() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 28]", "this.short123 = 1;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 28 */", "this.short123 = 1;"))); - assertTrue(source.matches(PatternMaker.make(": 32]", "super(short56);"))); - assertTrue(source.matches(PatternMaker.make(": 33]", "this.short123 = 2;"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "super(short56);"))); + assertTrue(source.matches(PatternMaker.make(": 33 */", "this.short123 = 2;"))); - assertTrue(source.matches(PatternMaker.make(": 37]", "this(short56);"))); - assertTrue(source.matches(PatternMaker.make(": 38]", "this.int78 = int78;"))); - assertTrue(source.matches(PatternMaker.make(": 39]", "this.short123 = 3;"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "this(short56);"))); + assertTrue(source.matches(PatternMaker.make(": 38 */", "this.int78 = int78;"))); + assertTrue(source.matches(PatternMaker.make(": 39 */", "this.short123 = 3;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170IfElse() throws Exception { + String internalClassName = "org/jd/core/test/IfElse"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -214,7 +225,7 @@ public void testJdk170IfElse() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/IfElse"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -230,48 +241,51 @@ public void testJdk170IfElse() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 12: 12]", "if (this == null)"))); - assertTrue(source.matches(PatternMaker.make("[ 22: 22]", "if (\"abc\".isEmpty() && \"abc\".isEmpty())"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 12: 12 */", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("/* 22: 22 */", "if (\"abc\".isEmpty() && \"abc\".isEmpty())"))); - assertTrue(source.matches(PatternMaker.make("[ 32: 32]", "if (this == null)"))); - assertTrue(source.matches(PatternMaker.make("[ 34: 0]", "} else {"))); + assertTrue(source.matches(PatternMaker.make("/* 32: 32 */", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("/* 34: 0 */", "} else {"))); - assertTrue(source.matches(PatternMaker.make("[ 44: 44]", "if (this == null)"))); - assertTrue(source.matches(PatternMaker.make("[ 46: 46]", "} else if (this == null) {"))); - assertTrue(source.matches(PatternMaker.make("[ 48: 0]", "} else {"))); + assertTrue(source.matches(PatternMaker.make("/* 44: 44 */", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("/* 46: 46 */", "} else if (this == null) {"))); + assertTrue(source.matches(PatternMaker.make("/* 48: 0 */", "} else {"))); - assertTrue(source.matches(PatternMaker.make("[ 58: 58]", "if (i == 0)"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 60]", "if (i == 1)"))); + assertTrue(source.matches(PatternMaker.make("/* 58: 58 */", "if (i == 0)"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 60 */", "if (i == 1)"))); - assertTrue(source.matches(PatternMaker.make("[ 71: 71]", "if (i == System.currentTimeMillis())"))); - assertTrue(source.matches(PatternMaker.make("[ 73: 73]", "} else if (i != System.currentTimeMillis()) {"))); - assertTrue(source.matches(PatternMaker.make("[ 75: 75]", "} else if (i > System.currentTimeMillis()) {"))); + assertTrue(source.matches(PatternMaker.make("/* 71: 71 */", "if (i == System.currentTimeMillis())"))); + assertTrue(source.matches(PatternMaker.make("/* 73: 73 */", "} else if (i != System.currentTimeMillis()) {"))); + assertTrue(source.matches(PatternMaker.make("/* 75: 75 */", "} else if (i > System.currentTimeMillis()) {"))); - assertTrue(source.matches(PatternMaker.make("[ 123: 123]", "if (i == 4 && i == 5 && i == 6)"))); + assertTrue(source.matches(PatternMaker.make("/* 123: 123 */", "if (i == 4 && i == 5 && i == 6)"))); - assertTrue(source.matches(PatternMaker.make("[ 135: 135]", "if (i == 3 || i == 5 || i == 6)"))); - assertTrue(source.matches(PatternMaker.make("[ 137: 137]", "} else if (i != 4 && i > 7 && i > 8) {"))); - assertTrue(source.matches(PatternMaker.make("[ 139: 0]", "} else {"))); + assertTrue(source.matches(PatternMaker.make("/* 135: 135 */", "if (i == 3 || i == 5 || i == 6)"))); + assertTrue(source.matches(PatternMaker.make("/* 137: 137 */", "} else if (i != 4 && i > 7 && i > 8) {"))); + assertTrue(source.matches(PatternMaker.make("/* 139: 0 */", "} else {"))); - assertTrue(source.matches(PatternMaker.make("[ 148: 148]", "if ((i == 1 && i == 2 && i == 3) || (i == 4 && i == 5 && i == 6) || (i == 7 && i == 8 && i == 9))"))); - assertTrue(source.matches(PatternMaker.make("[ 160: 160]", "if ((i == 1 || i == 2 || i == 3) && (i == 4 || i == 5 || i == 6) && (i == 7 || i == 8 || i == 9))"))); + assertTrue(source.matches(PatternMaker.make("/* 148: 148 */", "if ((i == 1 && i == 2 && i == 3) || (i == 4 && i == 5 && i == 6) || (i == 7 && i == 8 && i == 9))"))); + assertTrue(source.matches(PatternMaker.make("/* 160: 160 */", "if ((i == 1 || i == 2 || i == 3) && (i == 4 || i == 5 || i == 6) && (i == 7 || i == 8 || i == 9))"))); - assertTrue(source.matches(PatternMaker.make("[ 172: 172]", "if ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))"))); - assertTrue(source.matches(PatternMaker.make("[ 184: 184]", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); + assertTrue(source.matches(PatternMaker.make("/* 172: 172 */", "if ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))"))); + assertTrue(source.matches(PatternMaker.make("/* 184: 184 */", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170Interface() throws Exception { + String internalClassName = "org/jd/core/test/Interface"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Interface"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -286,15 +300,18 @@ public void testJdk170Interface() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.matches(PatternMaker.make("public interface Interface", "extends Serializable"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170While() throws Exception { + String internalClassName = "org/jd/core/test/While"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -302,7 +319,7 @@ public void testJdk170While() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/While"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -318,28 +335,31 @@ public void testJdk170While() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 15]", "while (i-- > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 23]", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 42]", "while (i0 > 20)"))); - assertTrue(source.matches(PatternMaker.make("[ 113: 0]", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 128: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 158: 0]", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 232]", "while (++i < 10)"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); - assertFalse(source.matches(PatternMaker.make("[ 348: 0]", "default:"))); - assertFalse(source.matches(PatternMaker.make("[ 350: 348]", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 404: 404]", "System.out.println(\"a\");"))); - assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); + assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk901While() throws Exception { + String internalClassName = "org/jd/core/test/While"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -347,7 +367,7 @@ public void testJdk901While() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/While"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -363,28 +383,31 @@ public void testJdk901While() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 15]", "while (i-- > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 23]", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 42]", "while (i0 > 20)"))); - assertTrue(source.matches(PatternMaker.make("[ 113: 0]", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 128: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 158: 0]", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 232]", "while (++i < 10)"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); - assertFalse(source.matches(PatternMaker.make("[ 348: 0]", "default:"))); - assertFalse(source.matches(PatternMaker.make("[ 350: 348]", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 404: 404]", "System.out.println(\"a\");"))); - assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); + assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk1002While() throws Exception { + String internalClassName = "org/jd/core/test/While"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -392,7 +415,7 @@ public void testJdk1002While() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/While"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -408,35 +431,38 @@ public void testJdk1002While() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 15]", "while (i-- > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 23]", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 42]", "while (i0 > 20)"))); - assertTrue(source.matches(PatternMaker.make("[ 113: 0]", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 128: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 158: 0]", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 232]", "while (++i < 10)"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); - assertFalse(source.matches(PatternMaker.make("[ 348: 0]", "default:"))); - assertFalse(source.matches(PatternMaker.make("[ 350: 348]", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 404: 404]", "System.out.println(\"a\");"))); - assertTrue(source.matches(PatternMaker.make("[ 431: 431]", "System.out.println(\"a\");"))); + assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170DoWhile() throws Exception { + String internalClassName = "org/jd/core/test/DoWhile"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/DoWhile"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -451,32 +477,35 @@ public void testJdk170DoWhile() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 24]", "} while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 32]", "} while (this == null);"))); - assertTrue(source.matches(PatternMaker.make(": 44]", "++i;"))); - assertTrue(source.matches(PatternMaker.make(": 46]", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 72]", "while (i0 < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 77]", "i1--;"))); - assertTrue(source.matches(PatternMaker.make(": 79]", "while (i1 > 0);"))); - assertTrue(source.matches(PatternMaker.make(": 98]", "while (--i > 0.0F);"))); - assertTrue(source.matches(PatternMaker.make(": 108]", "while (i-- > 0.0F);"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk901DoWhile() throws Exception { + String internalClassName = "org/jd/core/test/DoWhile"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/DoWhile"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -491,32 +520,35 @@ public void testJdk901DoWhile() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 24]", "} while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 32]", "} while (this == null);"))); - assertTrue(source.matches(PatternMaker.make(": 44]", "++i;"))); - assertTrue(source.matches(PatternMaker.make(": 46]", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 72]", "while (i0 < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 77]", "i1--;"))); - assertTrue(source.matches(PatternMaker.make(": 79]", "while (i1 > 0);"))); - assertTrue(source.matches(PatternMaker.make(": 98]", "while (--i > 0.0F);"))); - assertTrue(source.matches(PatternMaker.make(": 108]", "while (i-- > 0.0F);"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk1002DoWhile() throws Exception { + String internalClassName = "org/jd/core/test/DoWhile"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/DoWhile"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -531,25 +563,28 @@ public void testJdk1002DoWhile() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 24]", "} while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 32]", "} while (this == null);"))); - assertTrue(source.matches(PatternMaker.make(": 44]", "++i;"))); - assertTrue(source.matches(PatternMaker.make(": 46]", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 72]", "while (i0 < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 77]", "i1--;"))); - assertTrue(source.matches(PatternMaker.make(": 79]", "while (i1 > 0);"))); - assertTrue(source.matches(PatternMaker.make(": 98]", "while (--i > 0.0F);"))); - assertTrue(source.matches(PatternMaker.make(": 108]", "while (i-- > 0.0F);"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170BreakContinue() throws Exception { + String internalClassName = "org/jd/core/test/BreakContinue"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -557,7 +592,7 @@ public void testJdk170BreakContinue() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/BreakContinue"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -573,42 +608,45 @@ public void testJdk170BreakContinue() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 15: 15]", "if (i == 1)"))); - assertTrue(source.matches(PatternMaker.make("[ 16: 0]", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 18: 18]", "if (i == 2)"))); - assertTrue(source.matches(PatternMaker.make("[ 19: 0]", "continue;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "if (i == 1)"))); + assertTrue(source.matches(PatternMaker.make("/* 16: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "if (i == 2)"))); + assertTrue(source.matches(PatternMaker.make("/* 19: 0 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("[ 31: 31]", "label18: while (i > 1)"))); - assertTrue(source.matches(PatternMaker.make("[ 37: 0]", "continue label18;"))); - assertTrue(source.matches(PatternMaker.make("[ 40: 0]", "break label18;"))); + assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "label18: while (i > 1)"))); + assertTrue(source.matches(PatternMaker.make("/* 37: 0 */", "continue label18;"))); + assertTrue(source.matches(PatternMaker.make("/* 40: 0 */", "break label18;"))); - assertTrue(source.matches(PatternMaker.make("[ 54: 54]", "label17: while (i > 1)"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 63: 0]", "continue label17;"))); + assertTrue(source.matches(PatternMaker.make("/* 54: 54 */", "label17: while (i > 1)"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 63: 0 */", "continue label17;"))); - assertTrue(source.matches(PatternMaker.make("[ 78: 0]", "label13:"))); - assertTrue(source.matches(PatternMaker.make("[ 83: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 86: 0]", "break label13;"))); + assertTrue(source.matches(PatternMaker.make("/* 78: 0 */", "label13:"))); + assertTrue(source.matches(PatternMaker.make("/* 83: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 86: 0 */", "break label13;"))); - assertTrue(source.matches(PatternMaker.make("[ 101: 0]", "label15:", "do {"))); - assertTrue(source.matches(PatternMaker.make("[ 106: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 109: 0]", "break label15;"))); + assertTrue(source.matches(PatternMaker.make("/* 101: 0 */", "label15:", "do {"))); + assertTrue(source.matches(PatternMaker.make("/* 106: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 109: 0 */", "break label15;"))); - assertTrue(source.matches(PatternMaker.make("[ 123: 0]", "label24:", "do {"))); - assertTrue(source.matches(PatternMaker.make("[ 133: 0]", "continue label24;"))); - assertTrue(source.matches(PatternMaker.make("[ 135: 0]", "break label24;"))); - assertTrue(source.matches(PatternMaker.make("[ 138: 0]", "break label23;"))); + assertTrue(source.matches(PatternMaker.make("/* 123: 0 */", "label24:", "do {"))); + assertTrue(source.matches(PatternMaker.make("/* 133: 0 */", "continue label24;"))); + assertTrue(source.matches(PatternMaker.make("/* 135: 0 */", "break label24;"))); + assertTrue(source.matches(PatternMaker.make("/* 138: 0 */", "break label23;"))); - assertTrue(source.matches(PatternMaker.make("[ 155: 0]", "label16:", "do {"))); - assertTrue(source.matches(PatternMaker.make("[ 162: 0]", "break label16;"))); + assertTrue(source.matches(PatternMaker.make("/* 155: 0 */", "label16:", "do {"))); + assertTrue(source.matches(PatternMaker.make("/* 162: 0 */", "break label16;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170For() throws Exception { + String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -616,7 +654,7 @@ public void testJdk170For() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -632,61 +670,64 @@ public void testJdk170For() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 20]", "for (int i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 42]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 44]", "for (; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 54]", "for (; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 64]", "for (int i = 0;; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 72]", "for (;; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 80]", "for (int i = 0; i < 10;)"))); - assertTrue(source.matches(PatternMaker.make(": 88]", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 96]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make("[ 104: 0]", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 112]", "for (int i = 0, j = i, size = 10; i < size; j += ++i)"))); - assertTrue(source.matches(PatternMaker.make(": 122]", "int i = 0, j = i, size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 123]", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 124]", "j += ++i)"))); - assertTrue(source.matches(PatternMaker.make(": 134]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 135]", "int j = i;"))); - assertTrue(source.matches(PatternMaker.make(": 136]", "int size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 137]", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 138]", "i++,"))); - assertTrue(source.matches(PatternMaker.make(": 139]", "j += i)"))); - assertTrue(source.matches(PatternMaker.make(": 149]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 151]", "int j = i;"))); - assertTrue(source.matches(PatternMaker.make(": 153]", "int size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 155]", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 157]", "i++,"))); - assertTrue(source.matches(PatternMaker.make(": 159]", "j += i)"))); - assertTrue(source.matches(PatternMaker.make(": 169]", "for (int i = 0; i < 10; i++);"))); - assertTrue(source.matches(PatternMaker.make(": 177]", "for (; i < 10; i++);"))); - assertTrue(source.matches(PatternMaker.make(": 185]", "for (int i = 0;; i++);"))); - assertTrue(source.matches(PatternMaker.make("[ 190: 0]", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 191]", "i++;"))); - assertTrue(source.matches(PatternMaker.make(": 197]", "for (int i = 0; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 203]", "for (int[] i = { 0 }; i.length < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 209]", "for (int i = 0, j = i, k = i; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 215]", "for (int[] i = { 0 }, j = i, k = j; i.length < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 221]", "for (int i = 0, j[] = { 1 }; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 227]", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 233]", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make("[ 234: 0]", "while (true);"))); - assertTrue(source.matches(PatternMaker.make(": 245]", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); - assertTrue(source.matches(PatternMaker.make("[ 253: 0]", "while (true) {"))); - assertTrue(source.matches(PatternMaker.make(": 264]", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 310]", "for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make(": 389]", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 403]", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 411]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); - - assertTrue(source.indexOf("[ 489: 489]") != -1); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 54 */", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 64 */", "for (int i = 0;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "for (;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 80 */", "for (int i = 0; i < 10;)"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("/* 104: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 112 */", "for (int i = 0, j = i, size = 10; i < size; j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 122 */", "int i = 0, j = i, size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 123 */", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 134 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 135 */", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 136 */", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 137 */", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 138 */", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 139 */", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 149 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 151 */", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 153 */", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 155 */", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 157 */", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 159 */", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 169 */", "for (int i = 0; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 177 */", "for (; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 185 */", "for (int i = 0;; i++);"))); + assertTrue(source.matches(PatternMaker.make("/* 190: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 191 */", "i++;"))); + assertTrue(source.matches(PatternMaker.make(": 197 */", "for (int i = 0; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 203 */", "for (int[] i = { 0 }; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 209 */", "for (int i = 0, j = i, k = i; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 215 */", "for (int[] i = { 0 }, j = i, k = j; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 221 */", "for (int i = 0, j[] = { 1 }; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 227 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 233 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("/* 234: 0 */", "while (true);"))); + assertTrue(source.matches(PatternMaker.make(": 245 */", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); + assertTrue(source.matches(PatternMaker.make("/* 253: 0 */", "while (true) {"))); + assertTrue(source.matches(PatternMaker.make(": 264 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make(": 389 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 403 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + + assertTrue(source.indexOf("/* 489: 489 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170NoDebugFor() throws Exception { + String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -708,6 +749,7 @@ public void testJdk170NoDebugFor() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); assertTrue(source.matches(PatternMaker.make("for (byte b = 0;; b++)"))); assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); @@ -718,12 +760,14 @@ public void testJdk170NoDebugFor() throws Exception { assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + // TODO: fix error on line 168. assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk150For() throws Exception { + String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -731,7 +775,7 @@ public void testJdk150For() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -747,24 +791,27 @@ public void testJdk150For() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 16]", "for (byte b = 0; b < 10; b++)"))); - assertTrue(source.matches(PatternMaker.make(": 84]", "while (paramInt < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 269]", "for (paramInt = 0; paramInt < 10; paramInt++)"))); - assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("[ 343: 0]", "do {"))); - assertTrue(source.matches(PatternMaker.make(": 345]", "while (b < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 381]", "for (String str : paramArrayOfString)"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "for (String str : paramList)"))); - assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 423]", "for (byte b = 0; b < 3; b++)"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 16 */", "for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make(": 84 */", "while (paramInt < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 269 */", "for (paramInt = 0; paramInt < 10; paramInt++)"))); + assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 345 */", "while (b < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String str : paramArrayOfString)"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String str : paramList)"))); + assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 423 */", "for (byte b = 0; b < 3; b++)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + // TODO: fix error on line 205. assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk160For() throws Exception { + String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.6.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -772,7 +819,7 @@ public void testJdk160For() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -788,24 +835,27 @@ public void testJdk160For() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 16]", "for (int i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 84]", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 269]", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("[ 343: 0]", "do {"))); - assertTrue(source.matches(PatternMaker.make(": 345]", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 381]", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 16 */", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 84 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 269 */", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 423 */", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.6", new JavaSourceFileObject(internalClassName, source))); } @Test public void testIbmJ9For() throws Exception { + String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-ibm-j9_vm.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -813,7 +863,7 @@ public void testIbmJ9For() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -829,23 +879,26 @@ public void testIbmJ9For() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 84]", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 269]", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 306]", "for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("[ 343: 0]", "do"))); - assertTrue(source.matches(PatternMaker.make(": 345]", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 381]", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 407]", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 423]", "for (int i = 0; i < 3; i++)"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 84 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 269 */", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do"))); + assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 423 */", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170Array() throws Exception { + String internalClassName = "org/jd/core/test/Array"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -855,7 +908,7 @@ public void testJdk170Array() throws Exception { configuration.put("realignLineNumbers", Boolean.FALSE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Array"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -871,27 +924,30 @@ public void testJdk170Array() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 12]", "int[] i1 = new int[1];"))); - assertTrue(source.matches(PatternMaker.make(": 13]", "int[][] i2 = new int[1][];"))); - assertTrue(source.matches(PatternMaker.make(": 14]", "int[][][] i3 = new int[1][][];"))); - assertTrue(source.matches(PatternMaker.make(": 15]", "int[][][] i4 = new int[1][2][];"))); - assertTrue(source.matches(PatternMaker.make(": 22]", "String[][][][] s5 = new String[1][2][][];"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 12 */", "int[] i1 = new int[1];"))); + assertTrue(source.matches(PatternMaker.make(": 13 */", "int[][] i2 = new int[1][];"))); + assertTrue(source.matches(PatternMaker.make(": 14 */", "int[][][] i3 = new int[1][][];"))); + assertTrue(source.matches(PatternMaker.make(": 15 */", "int[][][] i4 = new int[1][2][];"))); + assertTrue(source.matches(PatternMaker.make(": 22 */", "String[][][][] s5 = new String[1][2][][];"))); - assertTrue(source.matches(PatternMaker.make(": 26]", "byte[] b1 = { 1, 2 } ;"))); - assertTrue(source.matches(PatternMaker.make(": 27]", "byte[][] b2 = { { 1, 2 } } ;"))); - assertTrue(source.matches(PatternMaker.make(": 28]", "byte[][][][] b3 = { { { 3, 4 } } } ;"))); + assertTrue(source.matches(PatternMaker.make(": 26 */", "byte[] b1 = { 1, 2 } ;"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "byte[][] b2 = { { 1, 2 } } ;"))); + assertTrue(source.matches(PatternMaker.make(": 28 */", "byte[][][][] b3 = { { { 3, 4 } } } ;"))); - assertTrue(source.matches(PatternMaker.make(": 48]", "testException1(new Exception[]", "{ new Exception(\"1\") } );"))); + assertTrue(source.matches(PatternMaker.make(": 48 */", "testException1(new Exception[]", "{ new Exception(\"1\") } );"))); - assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][]", "{ { 1 } ,"))); + assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][]", "{ { 1 } ,"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk150Array() throws Exception { + String internalClassName = "org/jd/core/test/Array"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -901,7 +957,7 @@ public void testJdk150Array() throws Exception { configuration.put("realignLineNumbers", Boolean.FALSE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Array"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -917,23 +973,26 @@ public void testJdk150Array() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 13]", "int[][] arrayOfInt1 = new int[1][];"))); - assertTrue(source.matches(PatternMaker.make(": 30]", "int[][] arrayOfInt1 = { { 0, 1, 2"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 13 */", "int[][] arrayOfInt1 = new int[1][];"))); + assertTrue(source.matches(PatternMaker.make(": 30 */", "int[][] arrayOfInt1 = { { 0, 1, 2"))); - assertTrue(source.matches(PatternMaker.make(": 52]", "testException2(new Exception[][]", "{ { new Exception(\"1\")"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "testException2(new Exception[][]", "{ { new Exception(\"1\")"))); - assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][] { { 1,"))); + assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][] { { 1,"))); - assertTrue(source.matches(PatternMaker.make(": 73]", "testInt2(new int[][] { { 1,"))); - assertTrue(source.matches(PatternMaker.make(": 75]", "testInt3(new int[][][] { { { 0, 1"))); + assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][] { { 1,"))); + assertTrue(source.matches(PatternMaker.make(": 75 */", "testInt3(new int[][][] { { { 0, 1"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170Assert() throws Exception { + String internalClassName = "org/jd/core/test/Assert"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -941,7 +1000,7 @@ public void testJdk170Assert() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Assert"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -957,21 +1016,24 @@ public void testJdk170Assert() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 16: 16]", "assert false : \"false\";"))); - assertTrue(source.matches(PatternMaker.make("[ 17: 17]", "assert i == 0 || i == 1;"))); - assertTrue(source.matches(PatternMaker.make("[ 18: 18]", "assert i == 2 && i < 3;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); + assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "assert i == 0 || i == 1;"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "assert i == 2 && i < 3;"))); - assertTrue(source.matches(PatternMaker.make("[ 34: 34]", "assert new BigDecimal(i) == BigDecimal.ONE;"))); + assertTrue(source.matches(PatternMaker.make("/* 34: 34 */", "assert new BigDecimal(i) == BigDecimal.ONE;"))); - assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); + assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk150Assert() throws Exception { + String internalClassName = "org/jd/core/test/Assert"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -979,7 +1041,7 @@ public void testJdk150Assert() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Assert"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -995,28 +1057,31 @@ public void testJdk150Assert() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 16: 16]", "assert false : \"false\";"))); - assertTrue(source.matches(PatternMaker.make("[ 17: 17]", "assert paramInt == 0 || paramInt == 1;"))); - assertTrue(source.matches(PatternMaker.make("[ 18: 18]", "assert paramInt == 2 && paramInt < 3;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); + assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "assert paramInt == 0 || paramInt == 1;"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "assert paramInt == 2 && paramInt < 3;"))); - assertTrue(source.matches(PatternMaker.make("[ 34: 34]", "assert new BigDecimal(paramInt) == BigDecimal.ONE;"))); + assertTrue(source.matches(PatternMaker.make("/* 34: 34 */", "assert new BigDecimal(paramInt) == BigDecimal.ONE;"))); - assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "assert check() : \"boom\";"))); + assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk150AnonymousClass() throws Exception { + String internalClassName = "org/jd/core/test/AnonymousClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/AnonymousClass"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -1031,30 +1096,34 @@ public void testJdk150AnonymousClass() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 21]", "Object object = new Object()"))); - assertTrue(source.matches(PatternMaker.make(": 23]", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 21 */", "Object object = new Object()"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); - assertTrue(source.matches(PatternMaker.make(": 37]", "final long l1 = System.currentTimeMillis();"))); - assertTrue(source.matches(PatternMaker.make(": 39]", "Enumeration enumeration = new Enumeration()"))); - assertTrue(source.matches(PatternMaker.make(": 40]", "Iterator i = AnonymousClass.this.list.iterator();"))); - assertTrue(source.matches(PatternMaker.make(": 44]", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "final long l1 = System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 39 */", "Enumeration enumeration = new Enumeration()"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "Iterator i = AnonymousClass.this.list.iterator();"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); assertTrue(source.indexOf("return this.i.next();") != -1); - assertTrue(source.matches(PatternMaker.make(": 52]", "test(enumeration, \"test\");"))); - assertTrue(source.matches(PatternMaker.make(": 55]", "System.out.println(\"end\");"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "test(enumeration, \"test\");"))); + assertTrue(source.matches(PatternMaker.make(": 55 */", "System.out.println(\"end\");"))); - assertTrue(source.matches(PatternMaker.make(": 67]", "if (s1 == s2 && i == 5)"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "if (s1 == s2 && i == 5)"))); - assertTrue(source.matches(PatternMaker.make(": 90]", "Serializable serializable = new Serializable()"))); - assertTrue(source.matches(PatternMaker.make(": 96]", "return (abc.equals(param2Object) || def.equals(param2Object) || str1.equals(param2Object) || str2.equals(param2Object));"))); - assertTrue(source.matches(PatternMaker.make(": 104]", "System.out.println(\"end\");"))); + assertTrue(source.matches(PatternMaker.make(": 90 */", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "return (abc.equals(param2Object) || def.equals(param2Object) || str1.equals(param2Object) || str2.equals(param2Object));"))); + assertTrue(source.matches(PatternMaker.make(": 104 */", "System.out.println(\"end\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}"))); } @Test public void testJdk170Switch() throws Exception { + String internalClassName = "org/jd/core/test/Switch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1062,7 +1131,7 @@ public void testJdk170Switch() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Switch"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1078,46 +1147,49 @@ public void testJdk170Switch() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 15: 15]", "switch (i)"))); - assertTrue(source.matches(PatternMaker.make("[ 16: 0]", "case 0:"))); - assertTrue(source.matches(PatternMaker.make("[ 17: 17]", "System.out.println(\"0\");"))); - assertTrue(source.matches(PatternMaker.make("[ 18: 0]", "break;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "switch (i)"))); + assertTrue(source.matches(PatternMaker.make("/* 16: 0 */", "case 0:"))); + assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "System.out.println(\"0\");"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 34: 0]", "case 0:"))); - assertTrue(source.matches(PatternMaker.make("[ 35: 35]", "System.out.println(\"0\");"))); - assertTrue(source.matches(PatternMaker.make("[ 36: 0]", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("/* 34: 0 */", "case 0:"))); + assertTrue(source.matches(PatternMaker.make("/* 35: 35 */", "System.out.println(\"0\");"))); + assertTrue(source.matches(PatternMaker.make("/* 36: 0 */", "case 1:"))); - assertTrue(source.matches(PatternMaker.make("[ 56: 0]", "default:"))); + assertTrue(source.matches(PatternMaker.make("/* 56: 0 */", "default:"))); - assertTrue(source.matches(PatternMaker.make("[ 110: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 111: 0]", "case 1:"))); - assertTrue(source.matches(PatternMaker.make("[ 112: 112]", "System.out.println(\"1\");"))); - assertTrue(source.matches(PatternMaker.make("[ 113: 113]", "throw new RuntimeException(\"boom\");"))); + assertTrue(source.matches(PatternMaker.make("/* 110: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 111: 0 */", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("/* 112: 112 */", "System.out.println(\"1\");"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 113 */", "throw new RuntimeException(\"boom\");"))); - assertTrue(source.matches(PatternMaker.make("[ 134: 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make("/* 134: 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make("[ 171: 0]", "case 3:"))); - assertTrue(source.matches(PatternMaker.make("[ 172: 0]", "case 4:"))); - assertTrue(source.matches(PatternMaker.make("[ 173: 173]", "System.out.println(\"3 or 4\");"))); - assertTrue(source.matches(PatternMaker.make("[ 174: 0]", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 171: 0 */", "case 3:"))); + assertTrue(source.matches(PatternMaker.make("/* 172: 0 */", "case 4:"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "System.out.println(\"3 or 4\");"))); + assertTrue(source.matches(PatternMaker.make("/* 174: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 265: 0]", "case 1:"))); - assertTrue(source.matches(PatternMaker.make("[ 266: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 267: 0]", "default:"))); + assertTrue(source.matches(PatternMaker.make("/* 265: 0 */", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("/* 266: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 267: 0 */", "default:"))); - assertTrue(source.matches(PatternMaker.make("[ 283: 0]", "case 1:"))); - assertTrue(source.matches(PatternMaker.make("[ 284: 0]", "case 2:"))); - assertTrue(source.matches(PatternMaker.make("[ 285: 0]", "case 3:"))); - assertTrue(source.matches(PatternMaker.make("[ 286: 0]", "break;"))); - assertTrue(source.matches(PatternMaker.make("[ 288: 0]", "default:"))); + assertTrue(source.matches(PatternMaker.make("/* 283: 0 */", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("/* 284: 0 */", "case 2:"))); + assertTrue(source.matches(PatternMaker.make("/* 285: 0 */", "case 3:"))); + assertTrue(source.matches(PatternMaker.make("/* 286: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 288: 0 */", "default:"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170AdvancedSwitch() throws Exception { + String internalClassName = "org/jd/core/test/AdvancedSwitch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1125,7 +1197,7 @@ public void testJdk170AdvancedSwitch() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/AdvancedSwitch"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1141,32 +1213,35 @@ public void testJdk170AdvancedSwitch() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 13: 13]", "A,", "B,", "C;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 13: 13 */", "A,", "B,", "C;"))); - assertTrue(source.matches(PatternMaker.make("[ 19: 19]", "switch (te)"))); - assertTrue(source.matches(PatternMaker.make("[ 20: 0]", "case A:"))); - assertTrue(source.matches(PatternMaker.make("[ 22: 0]", "case B:"))); - assertTrue(source.matches(PatternMaker.make("[ 25: 0]", "case C:"))); + assertTrue(source.matches(PatternMaker.make("/* 19: 19 */", "switch (te)"))); + assertTrue(source.matches(PatternMaker.make("/* 20: 0 */", "case A:"))); + assertTrue(source.matches(PatternMaker.make("/* 22: 0 */", "case B:"))); + assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "case C:"))); - assertTrue(source.matches(PatternMaker.make("[ 39: 0]", "case A:"))); - assertTrue(source.matches(PatternMaker.make("[ 40: 0]", "case B:"))); - assertTrue(source.matches(PatternMaker.make("[ 41: 41]", "System.out.println(\"A or B\");"))); + assertTrue(source.matches(PatternMaker.make("/* 39: 0 */", "case A:"))); + assertTrue(source.matches(PatternMaker.make("/* 40: 0 */", "case B:"))); + assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "System.out.println(\"A or B\");"))); - assertTrue(source.matches(PatternMaker.make("[ 56: 56]", "switch (str)"))); - assertTrue(source.matches(PatternMaker.make("[ 57: 0]", "case \"One\":"))); - assertTrue(source.matches(PatternMaker.make("[ 58: 58]", "System.out.println(1);"))); + assertTrue(source.matches(PatternMaker.make("/* 56: 56 */", "switch (str)"))); + assertTrue(source.matches(PatternMaker.make("/* 57: 0 */", "case \"One\":"))); + assertTrue(source.matches(PatternMaker.make("/* 58: 58 */", "System.out.println(1);"))); - assertTrue(source.matches(PatternMaker.make("[ 78: 0]", "case \"One\":"))); - assertTrue(source.matches(PatternMaker.make("[ 79: 0]", "case \"POe\":"))); - assertTrue(source.matches(PatternMaker.make("[ 80: 80]", "System.out.println(\"'One' or 'POe'\");"))); + assertTrue(source.matches(PatternMaker.make("/* 78: 0 */", "case \"One\":"))); + assertTrue(source.matches(PatternMaker.make("/* 79: 0 */", "case \"POe\":"))); + assertTrue(source.matches(PatternMaker.make("/* 80: 80 */", "System.out.println(\"'One' or 'POe'\");"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testEclipseJavaCompiler321Switch() throws Exception { + String internalClassName = "org/jd/core/test/Switch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1174,7 +1249,7 @@ public void testEclipseJavaCompiler321Switch() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Switch"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1190,14 +1265,17 @@ public void testEclipseJavaCompiler321Switch() throws Exception { printSource(source); - assertTrue(source.indexOf("[ 239: 239]") != -1); + // Check decompiled source code + assertTrue(source.indexOf("/* 239: 239 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testEclipseJavaCompiler3130Switch() throws Exception { + String internalClassName = "org/jd/core/test/Switch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1205,7 +1283,7 @@ public void testEclipseJavaCompiler3130Switch() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Switch"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1221,21 +1299,24 @@ public void testEclipseJavaCompiler3130Switch() throws Exception { printSource(source); - assertTrue(source.indexOf("[ 239: 239]") != -1); + // Check decompiled source code + assertTrue(source.indexOf("/* 239: 239 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk118TernaryOperator() throws Exception { + String internalClassName = "org/jd/core/test/TernaryOperator"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TernaryOperator"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -1250,35 +1331,38 @@ public void testJdk118TernaryOperator() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 13]", "this.str ="))); - assertTrue(source.matches(PatternMaker.make(": 14]", "(s == null) ?"))); - assertTrue(source.matches(PatternMaker.make(": 15]", "\"1\""))); - assertTrue(source.matches(PatternMaker.make(": 16]", "\"2\";"))); - assertTrue(source.matches(PatternMaker.make(": 24]", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); - assertTrue(source.matches(PatternMaker.make(": 34]", "return !(s != s || time < time);"))); - assertTrue(source.matches(PatternMaker.make(": 40]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 60]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 71]", "if ((s1 == null) ? false : (s1.length() > 0))"))); - assertTrue(source.matches(PatternMaker.make(": 82]", "if (s1 != null && s1.length() > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 126]", "if (s1 == null && false)"))); - assertTrue(source.matches(PatternMaker.make(": 137]", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 148]", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str ="))); + assertTrue(source.matches(PatternMaker.make(": 14 */", "(s == null) ?"))); + assertTrue(source.matches(PatternMaker.make(": 15 */", "\"1\""))); + assertTrue(source.matches(PatternMaker.make(": 16 */", "\"2\";"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); + assertTrue(source.matches(PatternMaker.make(": 34 */", "return !(s != s || time < time);"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 60 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 71 */", "if ((s1 == null) ? false : (s1.length() > 0))"))); + assertTrue(source.matches(PatternMaker.make(": 82 */", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 126 */", "if (s1 == null && false)"))); + assertTrue(source.matches(PatternMaker.make(": 137 */", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170TernaryOperator() throws Exception { + String internalClassName = "org/jd/core/test/TernaryOperator"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TernaryOperator"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -1293,25 +1377,28 @@ public void testJdk170TernaryOperator() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 13]", "this.str = (s == null) ? \"1\" : \"2\";"))); - assertTrue(source.matches(PatternMaker.make(": 24]", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); - assertTrue(source.matches(PatternMaker.make(": 34]", "return (s == s && time >= time);"))); - assertTrue(source.matches(PatternMaker.make(": 40]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 60]", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 71]", "if (s1 != null && s1.length() > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 82]", "if (s1 != null && s1.length() > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 126]", "if (s1 == null);"))); - assertTrue(source.matches(PatternMaker.make(": 137]", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 148]", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 157]", "return Short.toString((short)((this == null) ? 1 : 2));"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str = (s == null) ? \"1\" : \"2\";"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); + assertTrue(source.matches(PatternMaker.make(": 34 */", "return (s == s && time >= time);"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 60 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 71 */", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 82 */", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 126 */", "if (s1 == null);"))); + assertTrue(source.matches(PatternMaker.make(": 137 */", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170TryWithResources() throws Exception { + String internalClassName = "org/jd/core/test/TryWithResources"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1319,7 +1406,7 @@ public void testJdk170TryWithResources() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryWithResources"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1335,34 +1422,37 @@ public void testJdk170TryWithResources() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 12]", "try (FileInputStream input = new FileInputStream(path))"))); - - assertTrue(source.matches(PatternMaker.make(": 49]", "try (FileInputStream input = new FileInputStream(path))"))); - assertTrue(source.matches(PatternMaker.make(": 57]", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 59]", "System.out.println(\"finally\");"))); - - assertTrue(source.matches(PatternMaker.make(": 121]", "try(FileInputStream input = new FileInputStream(pathIn);"))); - assertTrue(source.matches(PatternMaker.make(": 122]", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); - assertTrue(source.matches(PatternMaker.make(": 123]", "FileOutputStream output = new FileOutputStream(pathOut);"))); - assertTrue(source.matches(PatternMaker.make(": 124]", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); - assertTrue(source.matches(PatternMaker.make(": 132]", "if (data == -7)"))); - assertTrue(source.matches(PatternMaker.make(": 133]", "return 1;"))); - assertTrue(source.matches(PatternMaker.make(": 142]", "return 2;"))); - assertTrue(source.matches(PatternMaker.make(": 144]", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 150]", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 152]", "System.out.println(\"finally, before loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 156]", "System.out.println(\"finally, after loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 159]", "System.out.println(\"finally\");"))); - assertTrue(source.matches(PatternMaker.make(": 162]", "return 3;"))); - - assertTrue(source.indexOf("[ 162: 162]") != -1); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); + + assertTrue(source.matches(PatternMaker.make(": 49 */", "try (FileInputStream input = new FileInputStream(path))"))); + assertTrue(source.matches(PatternMaker.make(": 57 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "System.out.println(\"finally\");"))); + + assertTrue(source.matches(PatternMaker.make(": 121 */", "try(FileInputStream input = new FileInputStream(pathIn);"))); + assertTrue(source.matches(PatternMaker.make(": 122 */", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); + assertTrue(source.matches(PatternMaker.make(": 123 */", "FileOutputStream output = new FileOutputStream(pathOut);"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); + assertTrue(source.matches(PatternMaker.make(": 132 */", "if (data == -7)"))); + assertTrue(source.matches(PatternMaker.make(": 133 */", "return 1;"))); + assertTrue(source.matches(PatternMaker.make(": 142 */", "return 2;"))); + assertTrue(source.matches(PatternMaker.make(": 144 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 150 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 152 */", "System.out.println(\"finally, before loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 156 */", "System.out.println(\"finally, after loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 159 */", "System.out.println(\"finally\");"))); + assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); + + assertTrue(source.indexOf("/* 162: 162 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk180TryWithResources() throws Exception { + String internalClassName = "org/jd/core/test/TryWithResources"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1370,7 +1460,7 @@ public void testJdk180TryWithResources() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryWithResources"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1386,41 +1476,44 @@ public void testJdk180TryWithResources() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 12]", "try (FileInputStream input = new FileInputStream(path))"))); - - assertTrue(source.matches(PatternMaker.make(": 49]", "try (FileInputStream input = new FileInputStream(path))"))); - assertTrue(source.matches(PatternMaker.make(": 57]", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 59]", "System.out.println(\"finally\");"))); - - assertTrue(source.matches(PatternMaker.make(": 121]", "try(FileInputStream input = new FileInputStream(pathIn);"))); - assertTrue(source.matches(PatternMaker.make(": 122]", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); - assertTrue(source.matches(PatternMaker.make(": 123]", "FileOutputStream output = new FileOutputStream(pathOut);"))); - assertTrue(source.matches(PatternMaker.make(": 124]", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); - assertTrue(source.matches(PatternMaker.make(": 132]", "if (data == -7)"))); - assertTrue(source.matches(PatternMaker.make(": 133]", "return 1;"))); - assertTrue(source.matches(PatternMaker.make(": 142]", "return 2;"))); - assertTrue(source.matches(PatternMaker.make(": 144]", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 150]", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 152]", "System.out.println(\"finally, before loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 156]", "System.out.println(\"finally, after loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 159]", "System.out.println(\"finally\");"))); - assertTrue(source.matches(PatternMaker.make(": 162]", "return 3;"))); - - assertTrue(source.indexOf("[ 162: 162]") != -1); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); + + assertTrue(source.matches(PatternMaker.make(": 49 */", "try (FileInputStream input = new FileInputStream(path))"))); + assertTrue(source.matches(PatternMaker.make(": 57 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "System.out.println(\"finally\");"))); + + assertTrue(source.matches(PatternMaker.make(": 121 */", "try(FileInputStream input = new FileInputStream(pathIn);"))); + assertTrue(source.matches(PatternMaker.make(": 122 */", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); + assertTrue(source.matches(PatternMaker.make(": 123 */", "FileOutputStream output = new FileOutputStream(pathOut);"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); + assertTrue(source.matches(PatternMaker.make(": 132 */", "if (data == -7)"))); + assertTrue(source.matches(PatternMaker.make(": 133 */", "return 1;"))); + assertTrue(source.matches(PatternMaker.make(": 142 */", "return 2;"))); + assertTrue(source.matches(PatternMaker.make(": 144 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 150 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 152 */", "System.out.println(\"finally, before loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 156 */", "System.out.println(\"finally, after loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 159 */", "System.out.println(\"finally\");"))); + assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); + + assertTrue(source.indexOf("/* 162: 162 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170Synchronised() throws Exception { + String internalClassName = "org/jd/core/test/Synchronized"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Synchronized"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -1435,32 +1528,35 @@ public void testJdk170Synchronised() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 11]", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 13]", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 15]", "return 2;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 11 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 13 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 15 */", "return 2;"))); - assertTrue(source.matches(PatternMaker.make(": 20]", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 22]", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 23]", "return 2;"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 22 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "return 2;"))); - assertTrue(source.matches(PatternMaker.make(": 29]", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 31]", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make(": 29 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 31 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make(": 73]", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 75]", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 76]", "throw new RuntimeException();"))); + assertTrue(source.matches(PatternMaker.make(": 73 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 75 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 76 */", "throw new RuntimeException();"))); - assertTrue(source.matches(PatternMaker.make(": 95]", "synchronized (s)"))); - assertTrue(source.matches(PatternMaker.make(": 97]", "return subContentEquals(s);"))); + assertTrue(source.matches(PatternMaker.make(": 95 */", "synchronized (s)"))); + assertTrue(source.matches(PatternMaker.make(": 97 */", "return subContentEquals(s);"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1468,7 +1564,7 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1484,13 +1580,14 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("[ 45: 45]", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make("/* 45: 45 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - assertTrue(source.indexOf("[ 888: 888]") != -1); + assertTrue(source.indexOf("/* 888: 888 */") != -1); assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); assertTrue(source.indexOf("catch (RuntimeException null)") == -1); @@ -1499,12 +1596,14 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1512,7 +1611,7 @@ public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1528,27 +1627,28 @@ public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); - assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); - assertTrue(source.indexOf("[ 400: 0] inFinally();") == -1); + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); + assertTrue(source.indexOf("/* 400: 0] inFinally();") == -1); - assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - assertTrue(source.indexOf("[ 888: 888]") != -1); + assertTrue(source.indexOf("/* 888: 888 */") != -1); assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); assertTrue(source.indexOf("catch (RuntimeException null)") == -1); @@ -1557,12 +1657,14 @@ public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1570,7 +1672,7 @@ public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1586,26 +1688,27 @@ public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); - assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - assertTrue(source.indexOf("[ 888: 888]") != -1); + assertTrue(source.indexOf("/* 888: 888 */") != -1); assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); assertTrue(source.indexOf("catch (RuntimeException null)") == -1); @@ -1614,12 +1717,14 @@ public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk118TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1627,7 +1732,7 @@ public void testJdk118TryCatchFinally() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1643,26 +1748,27 @@ public void testJdk118TryCatchFinally() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - assertTrue(source.indexOf("[ 902: 902]") != -1); + assertTrue(source.indexOf("/* 902: 902 */") != -1); assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); assertTrue(source.indexOf("catch (RuntimeException null)") == -1); @@ -1671,12 +1777,14 @@ public void testJdk118TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk131TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.3.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1684,7 +1792,7 @@ public void testJdk131TryCatchFinally() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1700,22 +1808,23 @@ public void testJdk131TryCatchFinally() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - assertTrue(source.indexOf("[ 902: 902]") != -1); + assertTrue(source.indexOf("/* 902: 902 */") != -1); assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); assertTrue(source.indexOf("catch (RuntimeException null)") == -1); @@ -1724,12 +1833,14 @@ public void testJdk131TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1737,7 +1848,7 @@ public void testJdk170TryCatchFinally() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/TryCatchFinally"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1753,29 +1864,30 @@ public void testJdk170TryCatchFinally() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("[ 48: 48]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("[ 60: 0]", "return;"))); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - assertTrue(source.matches(PatternMaker.make(": 166]", "return System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - assertTrue(source.matches(PatternMaker.make(": 192]", "catch (RuntimeException e) {}"))); - assertTrue(source.matches(PatternMaker.make("[ 204: 0]", "finally {}"))); + assertTrue(source.matches(PatternMaker.make(": 192 */", "catch (RuntimeException e) {}"))); + assertTrue(source.matches(PatternMaker.make("/* 204: 0 */", "finally {}"))); - assertTrue(source.matches(PatternMaker.make(": 393]", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395]", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397]", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 424]", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427]", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431]", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434]", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439]", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442]", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445]", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - assertTrue(source.indexOf("[ 902: 902]") != -1); + assertTrue(source.indexOf("/* 902: 902 */") != -1); assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); assertTrue(source.indexOf("catch (RuntimeException null)") == -1); @@ -1784,19 +1896,21 @@ public void testJdk170TryCatchFinally() throws Exception { assertTrue(source.indexOf("Exception exception8;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170AnnotatedClass() throws Exception { + String internalClassName = "org/jd/core/test/AnnotatedClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); // PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/AnnotatedClass"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -1811,6 +1925,7 @@ public void testJdk170AnnotatedClass() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("@Quality(Quality.Level.HIGH)") != -1); assertTrue(source.indexOf("@Author(value = @Name(salutation = \"Mr\", value = \"Donald\", last = \"Duck\"), contributors = {@Name(\"Huey\"), @Name(\"Dewey\"), @Name(\"Louie\")})") != -1); assertTrue(source.indexOf("@Value(z = true)") != -1); @@ -1826,12 +1941,18 @@ public void testJdk170AnnotatedClass() throws Exception { assertTrue(source.indexOf("public void ping(@Deprecated Writer writer, @Deprecated @Value(str = \"localhost\") String host, long timeout)") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Author", "package org.jd.core.test.annotation; public @interface Author {Name value(); Name[] contributors() default {};}"), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String salutation() default \"\"; String value(); String last() default \"\";}"), + new JavaSourceFileObject("org/jd/core/test/annotation/Quality", "package org.jd.core.test.annotation; public @interface Quality {enum Level {LOW,MIDDLE,HIGH}; Level value();}"), + new JavaSourceFileObject("org/jd/core/test/annotation/Value", "package org.jd.core.test.annotation; public @interface Value {boolean z() default true; byte b() default 1; short s() default 1; int i() default 1; long l() default 1L; float f() default 1.0F; double d() default 1.0D; String str() default \"str\"; Class clazz() default Object.class;}"))); } @Test public void testJdk170AnonymousClass() throws Exception { + String internalClassName = "org/jd/core/test/AnonymousClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); // PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1839,7 +1960,7 @@ public void testJdk170AnonymousClass() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/AnonymousClass"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1855,36 +1976,40 @@ public void testJdk170AnonymousClass() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 21]", "Object obj = new Object()"))); - assertTrue(source.matches(PatternMaker.make(": 23]", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 21 */", "Object obj = new Object()"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); - assertTrue(source.matches(PatternMaker.make(": 39]", "Enumeration e = new Enumeration()"))); - assertTrue(source.matches(PatternMaker.make(": 40]", "Iterator i = AnonymousClass.this.list.iterator();"))); - assertTrue(source.matches(PatternMaker.make(": 44]", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); + assertTrue(source.matches(PatternMaker.make(": 39 */", "Enumeration e = new Enumeration()"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "Iterator i = AnonymousClass.this.list.iterator();"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); - assertTrue(source.matches(PatternMaker.make(": 61]", "final int i = s1.length();"))); - assertTrue(source.matches(PatternMaker.make(": 63]", "System.out.println(\"2\" + new StringWrapper(123456L)"))); - assertTrue(source.matches(PatternMaker.make(": 67]", "if (s1 == s2 && i == 5)"))); - assertTrue(source.matches(PatternMaker.make("[ 72: 0]", "} + \"3\");"))); + assertTrue(source.matches(PatternMaker.make(": 61 */", "final int i = s1.length();"))); + assertTrue(source.matches(PatternMaker.make(": 63 */", "System.out.println(\"2\" + new StringWrapper(123456L)"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "if (s1 == s2 && i == 5)"))); + assertTrue(source.matches(PatternMaker.make("/* 72: 0 */", "} + \"3\");"))); - assertTrue(source.matches(PatternMaker.make(": 81]", "final Object abc = \"abc\";"))); - assertTrue(source.matches(PatternMaker.make(": 82]", "final Object def = \"def\";"))); - assertTrue(source.matches(PatternMaker.make(": 84]", "Serializable serializable = new Serializable()"))); - assertTrue(source.matches(PatternMaker.make(": 90]", "Serializable serializable = new Serializable()"))); - assertTrue(source.matches(PatternMaker.make(": 96]", "return (abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj));"))); - assertTrue(source.matches(PatternMaker.make(": 100]", "return (abc.equals(obj) || def.equals(obj));"))); - assertTrue(source.matches(PatternMaker.make("[ 102: 0]", "};"))); + assertTrue(source.matches(PatternMaker.make(": 81 */", "final Object abc = \"abc\";"))); + assertTrue(source.matches(PatternMaker.make(": 82 */", "final Object def = \"def\";"))); + assertTrue(source.matches(PatternMaker.make(": 84 */", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 90 */", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "return (abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj));"))); + assertTrue(source.matches(PatternMaker.make(": 100 */", "return (abc.equals(obj) || def.equals(obj));"))); + assertTrue(source.matches(PatternMaker.make("/* 102: 0 */", "};"))); - assertTrue(source.matches(PatternMaker.make(": 111]", "this.l = l & 0x80L;"))); + assertTrue(source.matches(PatternMaker.make(": 111 */", "this.l = l & 0x80L;"))); assertTrue(source.indexOf("} ;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}"))); } @Test public void testJdk170GenericClass() throws Exception { + String internalClassName = "org/jd/core/test/GenericClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -1892,7 +2017,7 @@ public void testJdk170GenericClass() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/GenericClass"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -1908,37 +2033,41 @@ public void testJdk170GenericClass() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.indexOf("public class GenericClass, T7 extends Map, T8 extends Map, T9 extends T8>") != -1); assertTrue(source.indexOf("extends ArrayList") != -1); assertTrue(source.indexOf("implements Serializable, Comparable") != -1); - assertTrue(source.matches(PatternMaker.make("[ 26: 26]", "public List> list1 = new ArrayList();"))); + assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "public List> list1 = new ArrayList();"))); assertTrue(source.indexOf("public List> list2;") != -1); - assertTrue(source.matches(PatternMaker.make("[ 31: 31]", "list2 = new ArrayList();"))); + assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "list2 = new ArrayList();"))); assertTrue(source.indexOf("public void fromArrayToCollection(T[] a, Collection c)") != -1); assertTrue(source.indexOf("public void copy(List dest, List src)") != -1); assertTrue(source.indexOf("public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException") != -1); assertTrue(source.indexOf("public List print(List list) throws T2, InvalidParameterException") != -1); - assertTrue(source.matches(PatternMaker.make(": 100]", "return (T1)call(0);"))); - assertTrue(source.matches(PatternMaker.make(": 104]", "return (T1)this;"))); + assertTrue(source.matches(PatternMaker.make(": 100 */", "return (T1)call(0);"))); + assertTrue(source.matches(PatternMaker.make(": 104 */", "return (T1)this;"))); - assertTrue(source.indexOf("[ 104: 104]") != -1); + assertTrue(source.indexOf("/* 104: 104 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/AnnotatedClass", "package org.jd.core.test; public class AnnotatedClass {}"))); } @Test public void testJdk170AnnotationAuthor() throws Exception { + String internalClassName = "org/jd/core/test/annotation/Author"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/annotation/Author"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -1953,24 +2082,28 @@ public void testJdk170AnnotationAuthor() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "public @interface Author"))); - assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "Name value();"))); - assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "Name[] contributors() default {};"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "public @interface Author"))); + assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "Name value();"))); + assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "Name[] contributors() default {};"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}"))); } @Test public void testJdk170AnnotationValue() throws Exception { + String internalClassName = "org/jd/core/test/annotation/Value"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/annotation/Value"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -1985,21 +2118,24 @@ public void testJdk170AnnotationValue() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "@Retention(RetentionPolicy.RUNTIME)"))); - assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})"))); - assertTrue(source.matches(PatternMaker.make("[ 10: 0]", "public @interface Value {"))); - assertTrue(source.matches(PatternMaker.make("[ 11: 0]", "boolean z() default true;"))); - assertTrue(source.matches(PatternMaker.make("[ 13: 0]", "byte b() default 1;"))); - assertTrue(source.matches(PatternMaker.make("[ 25: 0]", "String str() default \"str\";"))); - assertTrue(source.matches(PatternMaker.make("[ 27: 0]", "Class clazz() default Object.class;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "@Retention(RetentionPolicy.RUNTIME)"))); + assertTrue(source.matches(PatternMaker.make("/* 9: 0 */", "@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})"))); + assertTrue(source.matches(PatternMaker.make("/* 10: 0 */", "public @interface Value {"))); + assertTrue(source.matches(PatternMaker.make("/* 11: 0 */", "boolean z() default true;"))); + assertTrue(source.matches(PatternMaker.make("/* 13: 0 */", "byte b() default 1;"))); + assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "String str() default \"str\";"))); + assertTrue(source.matches(PatternMaker.make("/* 27: 0 */", "Class clazz() default Object.class;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170OuterClass() throws Exception { + String internalClassName = "org/jd/core/test/OuterClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //ClassPathLoader loader = new ClassPathLoader(); @@ -2008,7 +2144,7 @@ public void testJdk170OuterClass() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/OuterClass"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2024,65 +2160,68 @@ public void testJdk170OuterClass() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 10]", "protected int outerField1 = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 11]", "protected String[] outerField2 = { \"0\" };"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 10 */", "protected int outerField1 = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 11 */", "protected String[] outerField2 = { \"0\" };"))); assertTrue(source.indexOf("final int localVariable1 = param1;") != -1); assertTrue(source.indexOf("final String[] localVariable2 = param2;") != -1); - assertTrue(source.matches(PatternMaker.make(": 21]", "InnerClass innerClass = new InnerClass(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 22]", "innerClass.innerMethod(localVariable1, localVariable2);"))); - assertTrue(source.matches(PatternMaker.make(": 24]", "StaticInnerClass staticInnerClass = new StaticInnerClass(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 25]", "staticInnerClass.innerMethod(localVariable1, localVariable2);"))); + assertTrue(source.matches(PatternMaker.make(": 21 */", "InnerClass innerClass = new InnerClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 22 */", "innerClass.innerMethod(localVariable1, localVariable2);"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "StaticInnerClass staticInnerClass = new StaticInnerClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 25 */", "staticInnerClass.innerMethod(localVariable1, localVariable2);"))); - assertTrue(source.matches(PatternMaker.make(": 27]", "InnerClass anonymousClass = new InnerClass(param1, param2)"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "InnerClass anonymousClass = new InnerClass(param1, param2)"))); assertTrue(source.indexOf("public void innerMethod(int param1, String... param2)") != -1); - assertTrue(source.matches(PatternMaker.make(": 30]", "this.innerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 32]", "OuterClass.this.outerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 33]", "OuterClass.this.outerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 35]", "this.innerField1 = localVariable1;"))); - assertTrue(source.matches(PatternMaker.make(": 36]", "this.innerField2 = localVariable2;"))); - - assertTrue(source.matches(PatternMaker.make(": 39]", "anonymousClass.innerMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make(": 41]", "StaticInnerClass staticAnonymousClass = new StaticInnerClass(param1, param2)"))); - assertTrue(source.matches(PatternMaker.make(": 44]", "this.innerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 46]", "OuterClass.this.outerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 47]", "OuterClass.this.outerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 49]", "this.innerField1 = localVariable1;"))); - assertTrue(source.matches(PatternMaker.make(": 50]", "this.innerField2 = localVariable2;"))); - - assertTrue(source.matches(PatternMaker.make(": 53]", "staticAnonymousClass.innerMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make(": 55]", "InnerEnum.A.innerMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make("[ 56: 0]", "class LocalClass"))); - assertTrue(source.matches(PatternMaker.make(": 58]", "protected int innerField1 = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 59]", "protected String[] innerField2 = { \"0\" } ;"))); - assertTrue(source.matches(PatternMaker.make(": 69]", "this.innerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 70]", "this.innerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 72]", "OuterClass.this.outerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 73]", "OuterClass.this.outerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 75]", "this.innerField1 = localVariable1;"))); - assertTrue(source.matches(PatternMaker.make(": 76]", "this.innerField2 = localVariable2;"))); - assertTrue(source.matches(PatternMaker.make(": 94]", "LocalClass localClass = new LocalClass(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 95]", "localClass.localMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make(": 114]", "this(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 144]", "this(param1, param2);"))); - - assertTrue(source.matches(PatternMaker.make(": 158]", "A,", "B,", "C;"))); - assertTrue(source.indexOf("[ 182: 182]") != -1); + assertTrue(source.matches(PatternMaker.make(": 30 */", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 33 */", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 35 */", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 36 */", "this.innerField2 = localVariable2;"))); + + assertTrue(source.matches(PatternMaker.make(": 39 */", "anonymousClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 41 */", "StaticInnerClass staticAnonymousClass = new StaticInnerClass(param1, param2)"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 47 */", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "this.innerField2 = localVariable2;"))); + + assertTrue(source.matches(PatternMaker.make(": 53 */", "staticAnonymousClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 55 */", "InnerEnum.A.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make("/* 56: 0 */", "class LocalClass"))); + assertTrue(source.matches(PatternMaker.make(": 58 */", "protected int innerField1 = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "protected String[] innerField2 = { \"0\" } ;"))); + assertTrue(source.matches(PatternMaker.make(": 69 */", "this.innerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 70 */", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 73 */", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 75 */", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 76 */", "this.innerField2 = localVariable2;"))); + assertTrue(source.matches(PatternMaker.make(": 94 */", "LocalClass localClass = new LocalClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 95 */", "localClass.localMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 114 */", "this(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 144 */", "this(param1, param2);"))); + + assertTrue(source.matches(PatternMaker.make(": 158 */", "A,", "B,", "C;"))); + assertTrue(source.indexOf("/* 182: 182 */") != -1); assertTrue(source.matches(PatternMaker.make("public class InnerInnerClass", "{", "}"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk170Enum() throws Exception { + String internalClassName = "org/jd/core/test/Enum"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -2090,7 +2229,7 @@ public void testJdk170Enum() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Enum"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2106,29 +2245,32 @@ public void testJdk170Enum() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 5]", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); - assertTrue(source.matches(PatternMaker.make(": 9]", "MERCURY(3.303E23D, 2439700.0D),"))); - assertTrue(source.matches(PatternMaker.make(": 17]", "URANUS(8.686E25D, 2.5559E7D),"))); - assertTrue(source.matches(PatternMaker.make(": 20]", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); assertTrue(source.indexOf("this.mass = mass;") != -1); - assertTrue(source.matches(PatternMaker.make(": 27]", "this.radius = radius;"))); - assertTrue(source.matches(PatternMaker.make(": 37]", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); - assertTrue(source.matches(PatternMaker.make(": 49]", "double earthWeight = Double.parseDouble(args[0]);"))); - assertTrue(source.matches(PatternMaker.make(": 50]", "double mass = earthWeight / EARTH.surfaceGravity();"))); - assertTrue(source.matches(PatternMaker.make(": 51]", "for (Planet p : values()) {"))); - assertTrue(source.matches(PatternMaker.make(": 52]", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); assertTrue(source.indexOf("public static final enum") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk901Enum() throws Exception { + String internalClassName = "org/jd/core/test/Enum"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -2136,7 +2278,7 @@ public void testJdk901Enum() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Enum"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2152,29 +2294,32 @@ public void testJdk901Enum() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 5]", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); - assertTrue(source.matches(PatternMaker.make(": 9]", "MERCURY(3.303E23D, 2439700.0D),"))); - assertTrue(source.matches(PatternMaker.make(": 17]", "URANUS(8.686E25D, 2.5559E7D),"))); - assertTrue(source.matches(PatternMaker.make(": 20]", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); assertTrue(source.indexOf("this.mass = mass;") != -1); - assertTrue(source.matches(PatternMaker.make(": 27]", "this.radius = radius;"))); - assertTrue(source.matches(PatternMaker.make(": 37]", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); - assertTrue(source.matches(PatternMaker.make(": 49]", "double earthWeight = Double.parseDouble(args[0]);"))); - assertTrue(source.matches(PatternMaker.make(": 50]", "double mass = earthWeight / EARTH.surfaceGravity();"))); - assertTrue(source.matches(PatternMaker.make(": 51]", "for (Planet p : values()) {"))); - assertTrue(source.matches(PatternMaker.make(": 52]", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); assertTrue(source.indexOf("public static final enum") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk1002Enum() throws Exception { + String internalClassName = "org/jd/core/test/Enum"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -2182,7 +2327,7 @@ public void testJdk1002Enum() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Enum"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2198,29 +2343,32 @@ public void testJdk1002Enum() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 5]", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); - assertTrue(source.matches(PatternMaker.make(": 9]", "MERCURY(3.303E23D, 2439700.0D),"))); - assertTrue(source.matches(PatternMaker.make(": 17]", "URANUS(8.686E25D, 2.5559E7D),"))); - assertTrue(source.matches(PatternMaker.make(": 20]", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); assertTrue(source.indexOf("this.mass = mass;") != -1); - assertTrue(source.matches(PatternMaker.make(": 27]", "this.radius = radius;"))); - assertTrue(source.matches(PatternMaker.make(": 37]", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); - assertTrue(source.matches(PatternMaker.make(": 49]", "double earthWeight = Double.parseDouble(args[0]);"))); - assertTrue(source.matches(PatternMaker.make(": 50]", "double mass = earthWeight / EARTH.surfaceGravity();"))); - assertTrue(source.matches(PatternMaker.make(": 51]", "for (Planet p : values()) {"))); - assertTrue(source.matches(PatternMaker.make(": 52]", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); assertTrue(source.indexOf("public static final enum") == -1); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk118Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -2228,7 +2376,7 @@ public void testJdk118Basic() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2244,20 +2392,23 @@ public void testJdk118Basic() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make(": 126]", "int int78 = getInt78(new Object[] { this }, (short)5);"))); - assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return String.valueOf(str) + str;"))); - assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); + assertTrue(source.matches(PatternMaker.make(": 126 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return String.valueOf(str) + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk142Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.4.2.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -2265,7 +2416,7 @@ public void testJdk142Basic() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2281,23 +2432,26 @@ public void testJdk142Basic() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 18]", "protected short short56 = 56;"))); - assertTrue(source.matches(PatternMaker.make(": 19]", "protected int int78 = 78;"))); - assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); - assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.4", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk901Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -2305,7 +2459,7 @@ public void testJdk901Basic() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2321,23 +2475,26 @@ public void testJdk901Basic() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 18]", "protected short short56 = 56;"))); - assertTrue(source.matches(PatternMaker.make(": 19]", "protected int int78 = 78;"))); - assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); - assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk1002Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -2345,7 +2502,7 @@ public void testJdk1002Basic() throws Exception { Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Basic"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); message.setHeader("configuration", configuration); @@ -2361,30 +2518,33 @@ public void testJdk1002Basic() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 18]", "protected short short56 = 56;"))); - assertTrue(source.matches(PatternMaker.make(": 19]", "protected int int78 = 78;"))); - assertTrue(source.matches(PatternMaker.make(": 43]", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("[ 171: 171]", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("[ 174: 174]", "return str;"))); - assertTrue(source.matches(PatternMaker.make("[ 183: 183]", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("[ 186: 186]", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk180Lambda() throws Exception { + String internalClassName = "org/jd/core/test/Lambda"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/Lambda"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -2399,37 +2559,40 @@ public void testJdk180Lambda() throws Exception { printSource(source); - assertTrue(source.matches(PatternMaker.make(": 16]", "list.forEach(System.out::println);"))); - assertTrue(source.matches(PatternMaker.make(": 20]", "list.stream().filter(s -> (s != null)).forEach(s -> System.out.println(s));"))); + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 16 */", "list.forEach(System.out::println);"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "list.stream().filter(s -> (s != null)).forEach(s -> System.out.println(s));"))); assertTrue(source.indexOf("Predicate filter = s -> (s.length() == length);") != -1); assertTrue(source.indexOf("Consumer println = s -> System.out.println(s);") != -1); - assertTrue(source.matches(PatternMaker.make(": 27]", "list.stream().filter(filter).forEach(println);"))); - assertTrue(source.matches(PatternMaker.make(": 31]", "((Map)list.stream()"))); - assertTrue(source.matches(PatternMaker.make(": 32]", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))"))); - assertTrue(source.matches(PatternMaker.make(": 33]", ".forEach((key, value) ->"))); - assertTrue(source.matches(PatternMaker.make(": 48]", "Thread thread = new Thread(() -> {"))); - assertTrue(source.matches(PatternMaker.make(": 58]", "Consumer staticMethodReference = String::valueOf;"))); - assertTrue(source.matches(PatternMaker.make(": 59]", "BiFunction methodReference = String::compareTo;"))); - assertTrue(source.matches(PatternMaker.make(": 60]", "Supplier instanceMethodReference = s::toString;"))); - assertTrue(source.matches(PatternMaker.make(": 61]", "Supplier constructorReference = String::new;"))); - assertTrue(source.matches(PatternMaker.make(": 65]", "MethodType mtToString = MethodType.methodType(String.class);"))); - assertTrue(source.matches(PatternMaker.make(": 66]", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); - assertTrue(source.matches(PatternMaker.make(": 67]", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter(filter).forEach(println);"))); + assertTrue(source.matches(PatternMaker.make(": 31 */", "((Map)list.stream()"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))"))); + assertTrue(source.matches(PatternMaker.make(": 33 */", ".forEach((key, value) ->"))); + assertTrue(source.matches(PatternMaker.make(": 48 */", "Thread thread = new Thread(() -> {"))); + assertTrue(source.matches(PatternMaker.make(": 58 */", "Consumer staticMethodReference = String::valueOf;"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "BiFunction methodReference = String::compareTo;"))); + assertTrue(source.matches(PatternMaker.make(": 60 */", "Supplier instanceMethodReference = s::toString;"))); + assertTrue(source.matches(PatternMaker.make(": 61 */", "Supplier constructorReference = String::new;"))); + assertTrue(source.matches(PatternMaker.make(": 65 */", "MethodType mtToString = MethodType.methodType(String.class);"))); + assertTrue(source.matches(PatternMaker.make(": 66 */", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @Test public void testJdk901InterfaceWithDefaultMethods() throws Exception { + String internalClassName = "org/jd/core/test/InterfaceWithDefaultMethods"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/InterfaceWithDefaultMethods"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -2444,20 +2607,30 @@ public void testJdk901InterfaceWithDefaultMethods() throws Exception { printSource(source); + // Check decompiled source code assertTrue(source.matches(PatternMaker.make("public interface InterfaceWithDefaultMethods"))); assertTrue(source.matches(PatternMaker.make("void setTime(int paramInt1, int paramInt2, int paramInt3);"))); assertTrue(source.matches(PatternMaker.make("LocalDateTime getLocalDateTime();"))); assertTrue(source.matches(PatternMaker.make("static ZoneId getZoneId(String zoneString)"))); - assertTrue(source.matches(PatternMaker.make(": 24]", "return unsafeGetZoneId(zoneString);"))); - assertTrue(source.matches(PatternMaker.make(": 26]", "System.err.println(\"Invalid time zone: \" + zoneString + \"; using default time zone instead.\");"))); - assertTrue(source.matches(PatternMaker.make(": 27]", "return ZoneId.systemDefault();"))); - assertTrue(source.matches(PatternMaker.make(": 32]", "default ZonedDateTime getZonedDateTime(String zoneString) { return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString)); }"))); - assertTrue(source.matches(PatternMaker.make(": 36]", "private static ZoneId unsafeGetZoneId(String zoneString) { return ZoneId.of(zoneString); }"))); - assertTrue(source.matches(PatternMaker.make(": 40]", "private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId) { return ZonedDateTime.of(localDateTime, zoneId); }"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "return unsafeGetZoneId(zoneString);"))); + assertTrue(source.matches(PatternMaker.make(": 26 */", "System.err.println(\"Invalid time zone: \" + zoneString + \"; using default time zone instead.\");"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "return ZoneId.systemDefault();"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "default ZonedDateTime getZonedDateTime(String zoneString) { return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString)); }"))); + assertTrue(source.matches(PatternMaker.make(": 36 */", "private static ZoneId unsafeGetZoneId(String zoneString) { return ZoneId.of(zoneString); }"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId) { return ZonedDateTime.of(localDateTime, zoneId); }"))); assertTrue(source.indexOf("// Byte code:") == -1); - assertTrue(source.indexOf(".null.") == -1 && source.indexOf(".null ") == -1 && source.indexOf("null = ") == -1); - assertTrue(source.indexOf("/* ") == -1); + + // Recompile decompiled source code and check errors + try { + assertTrue(CompilerUtil.compile("1.9", new JavaSourceFileObject(internalClassName, source))); + } catch (IllegalArgumentException e) { + if (e.getMessage().contains("invalid source release: 1.9")) { + System.err.println("testJdk901InterfaceWithDefaultMethods() need a Java SDK 9+"); + } else { + assertTrue("Compilation failed: " + e.getMessage(), false); + } + } } protected void printSource(String source) { diff --git a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java index 24cb2b5c..b3c35d8d 100644 --- a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java +++ b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -22,7 +22,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.processor.ConvertClassFileProcessor; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.*; import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; -import org.jd.core.v1.util.ControlFlowGraphPlantUMLWriter; +import org.jd.core.v1.cfg.ControlFlowGraphPlantUMLWriter; import org.junit.Test; import java.io.FileInputStream; diff --git a/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java b/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java index 9e93dd38..96554796 100644 --- a/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java +++ b/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -19,7 +19,7 @@ import org.jd.core.v1.service.writer.WriteTokenProcessor; import org.jd.core.v1.services.tokenizer.javafragmenttotoken.TestTokenizeJavaFragmentProcessor; import org.jd.core.v1.util.DefaultList; -import org.jd.core.v1.util.PatternMaker; +import org.jd.core.v1.regex.PatternMaker; import org.junit.Assert; import org.junit.Test; diff --git a/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java b/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java index 458cd923..f2061d84 100644 --- a/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java +++ b/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -18,7 +18,7 @@ import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; import org.jd.core.v1.service.writer.WriteTokenProcessor; import org.jd.core.v1.services.tokenizer.javafragmenttotoken.TestTokenizeJavaFragmentProcessor; -import org.jd.core.v1.util.PatternMaker; +import org.jd.core.v1.regex.PatternMaker; import org.junit.Assert; import org.junit.Test; diff --git a/src/test/java/org/jd/core/v1/util/ControlFlowGraphPlantUMLWriter.java b/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java similarity index 99% rename from src/test/java/org/jd/core/v1/util/ControlFlowGraphPlantUMLWriter.java rename to src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java index b7eac98f..0cf8ac0b 100644 --- a/src/test/java/org/jd/core/v1/util/ControlFlowGraphPlantUMLWriter.java +++ b/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java @@ -1,16 +1,17 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. */ -package org.jd.core.v1.util; +package org.jd.core.v1.cfg; import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ByteCodeWriter; +import org.jd.core.v1.util.DefaultList; import java.util.Comparator; import java.util.HashSet; diff --git a/src/test/java/org/jd/core/v1/compiler/CompilerUtil.java b/src/test/java/org/jd/core/v1/compiler/CompilerUtil.java new file mode 100644 index 00000000..6eeee267 --- /dev/null +++ b/src/test/java/org/jd/core/v1/compiler/CompilerUtil.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.compiler; + +import javax.tools.*; +import java.io.File; +import java.io.StringWriter; +import java.util.Arrays; + +public class CompilerUtil { + protected static final File DESTINATION_DIRECTORY = new File("build/test-recompiled"); + protected static final String DESTINATION_DIRECTORY_PATH = DESTINATION_DIRECTORY.getAbsolutePath(); + + public static boolean compile(String javaVersion, JavaFileObject... JavaFileObjects) throws Exception { + boolean compilationSuccess = false; + + DESTINATION_DIRECTORY.mkdirs(); + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StringWriter writer = new StringWriter(); + DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + + try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) { + Iterable options = Arrays.asList("-source", javaVersion, "-target", javaVersion, "-d", DESTINATION_DIRECTORY_PATH); + Iterable compilationUnits = Arrays.asList(JavaFileObjects); + compilationSuccess = compiler.getTask(writer, fileManager, diagnostics, options, null, compilationUnits).call(); + + for (Diagnostic d : diagnostics.getDiagnostics()) { + if (d.getLineNumber() > 0) { + System.err.print(String.format("%-7s - line %-4d- %s%n", d.getKind(), d.getLineNumber(), d.getMessage(null))); + } else { + System.err.print(String.format("%-7s - - %s%n", d.getKind(), d.getMessage(null))); + } + } + } + + return compilationSuccess; + } +} diff --git a/src/test/java/org/jd/core/v1/compiler/JavaSourceFileObject.java b/src/test/java/org/jd/core/v1/compiler/JavaSourceFileObject.java new file mode 100644 index 00000000..a5cf67c4 --- /dev/null +++ b/src/test/java/org/jd/core/v1/compiler/JavaSourceFileObject.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.compiler; + +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import java.net.URI; + +public class JavaSourceFileObject extends SimpleJavaFileObject { + /** + * The source code of this "file". + */ + final String code; + + /** + * Constructs a new JavaSourceFromString. + * @param name the name of the compilation unit represented by this file object + * @param code the source code for the compilation unit represented by this file object + */ + public JavaSourceFileObject(String name, String code) { + super(URI.create("string:///" + name.replace('.','/') + JavaFileObject.Kind.SOURCE.extension), JavaFileObject.Kind.SOURCE); + this.code = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } +} diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java index 8b6b48da..539bf684 100644 --- a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java +++ b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,10 +11,10 @@ import org.jd.core.v1.api.printer.Printer; public class PlainTextPrinter implements Printer { - protected static final String TAB = " "; - protected static final String NEWLINE = "\n"; + protected static final String TAB = " "; + protected static final String NEWLINE = "\n"; - protected int indentationCount; + protected int indentationCount; protected StringBuilder sb = new StringBuilder(); protected int realLineNumber = 0; protected String format; @@ -117,10 +117,10 @@ public void startMarker(int type) {} public void endMarker(int type) {} protected void printLineNumber(int lineNumber) { - sb.append('['); + sb.append("/*"); sb.append(String.format(format, ++realLineNumber)); sb.append(':'); sb.append(String.format(format, lineNumber)); - sb.append("] "); + sb.append(" */ "); } } diff --git a/src/test/java/org/jd/core/v1/util/PatternMaker.java b/src/test/java/org/jd/core/v1/regex/PatternMaker.java similarity index 94% rename from src/test/java/org/jd/core/v1/util/PatternMaker.java rename to src/test/java/org/jd/core/v1/regex/PatternMaker.java index d1463a7a..4bc8183b 100644 --- a/src/test/java/org/jd/core/v1/util/PatternMaker.java +++ b/src/test/java/org/jd/core/v1/regex/PatternMaker.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. */ -package org.jd.core.v1.util; +package org.jd.core.v1.regex; public class PatternMaker { public static String make (String first, String... next) { From 2cb045707ee9d3234b12e095964ba164fdd6ea0f Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 29 Jul 2019 10:48:00 +0200 Subject: [PATCH 051/211] Update unit tests --- .../jd/core/v1/JavaFragmentToTokenTest.java | 228 +++++++++--------- .../core/v1/JavaSyntaxToJavaSourceTest.java | 8 +- .../core/v1/LayoutFragmentProcessorTest.java | 16 +- .../java/org/jd/core/v1/WriteTokenTest.java | 50 ++-- 4 files changed, 151 insertions(+), 151 deletions(-) diff --git a/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java b/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java index 96554796..ff185694 100644 --- a/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java +++ b/src/test/java/org/jd/core/v1/JavaFragmentToTokenTest.java @@ -70,7 +70,7 @@ public void testIfReturn_0() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "i = 1;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "i = 1;"))); } @Test @@ -93,9 +93,9 @@ public void testIfReturn_1_3() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "return;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "int i = 1;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 1 */", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 0 */", "return;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 3 */", "int i = 1;"))); } @Test @@ -118,9 +118,9 @@ public void testIfReturn_1_4() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "return;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 4]", "int i = 1;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 1 */", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 0 */", "return;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 4 */", "int i = 1;"))); } @Test @@ -141,7 +141,7 @@ public void testIfAssignation_0() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "i = 1;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "i = 1;"))); } @Test @@ -164,9 +164,9 @@ public void testIfAssignation_1_2_3() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 2]", "i = 0;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "i = 1;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 1 */", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 2 */", "i = 0;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 3 */", "i = 1;"))); Assert.assertTrue(source.indexOf('{') == -1); } @@ -190,10 +190,10 @@ public void testIfAssignation_1_3_5() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 1]", "if (args == null)"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "{"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "i = 0;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 5: 5]", "i = 1;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 1 */", "if (args == null)"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 0 */", "{"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 3 */", "i = 0;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 5: 5 */", "i = 1;"))); } @Test @@ -214,7 +214,7 @@ public void testClassAndFieldDeclarationWithoutImports_0() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "protected int a"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "protected int a"))); } @Test @@ -235,7 +235,7 @@ public void testClassAndFieldDeclaration_0() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "protected int a"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 7: 0 */", "protected int a"))); } @Test @@ -258,8 +258,8 @@ public void testClassAndFieldDeclaration_1() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 1] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.indexOf("[ 2: 0] -->") != -1); + Assert.assertTrue(source.indexOf("/* 1: 1 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.indexOf("/* 2: 0 */ -->") != -1); } @Test @@ -282,8 +282,8 @@ public void testClassAndFieldDeclaration_2() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 2]", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 2 */", "protected int a"))); } @Test @@ -306,10 +306,10 @@ public void testClassAndFieldDeclaration_3() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "protected int a"))); - Assert.assertTrue(source.indexOf("[ 4: 0] } -->") != -1); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 3 */", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 4: 0 */ } -->") != -1); } @Test @@ -332,10 +332,10 @@ public void testClassAndFieldDeclaration_4() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 4]", "protected int a"))); - Assert.assertTrue(source.indexOf("[ 5: 0] } -->") != -1); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 4 */", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 5: 0 */ } -->") != -1); } @Test @@ -358,9 +358,9 @@ public void testClassAndFieldDeclaration_5() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 5: 5]", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 5: 5 */", "protected int a"))); } @Test @@ -383,10 +383,10 @@ public void testClassAndFieldDeclaration_6() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 5: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 6]", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 5: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 6 */", "protected int a"))); } @Test @@ -407,11 +407,11 @@ public void testClassAndFieldDeclaration_7() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 7]", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 7: 7 */", "protected int a"))); } @Test @@ -434,11 +434,11 @@ public void testClassAndFieldDeclaration_8() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 8]", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 8: 8 */", "protected int a"))); } @Test @@ -461,11 +461,11 @@ public void testClassAndFieldDeclaration_9() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 9]", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 9: 9 */", "protected int a"))); } @Test @@ -489,11 +489,11 @@ public void testClassAndFieldDeclaration_10() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 10]", "protected int a"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 10: 10 */", "protected int a"))); } @Test @@ -516,9 +516,9 @@ public void testClassAndMethodDeclaration_3() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "public TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 3]", "super(i);"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 0 */", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 3 */", "super(i);"))); } @Test @@ -541,9 +541,9 @@ public void testClassAndMethodDeclaration_4() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 2: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "public TokenWriterTest", "(int i)"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 2: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "public TokenWriterTest", "(int i)"))); } @Test @@ -564,11 +564,11 @@ public void testClassAndMethodDeclaration_8() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "public TokenWriterTest", "(int i)"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 7: 0 */", "public TokenWriterTest", "(int i)"))); } @Test @@ -591,11 +591,11 @@ public void testClassAndMethodDeclaration_9() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.writer;") != -1); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "public TokenWriterTest", "(int i)"))); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.writer;") != -1); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "public TokenWriterTest", "(int i)"))); } @Test @@ -619,14 +619,14 @@ public void testClassAndMethodDeclaration_10() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "extends Test"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "implements Serializable"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "public TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 10]", "super"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 0 */", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 7: 0 */", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 9: 0 */", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 10: 10 */", "super"))); } @Test @@ -650,14 +650,14 @@ public void testClassAndMethodDeclaration_11() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 6: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "extends Test"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "implements Serializable"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 0]", "public TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 11: 11]", "super"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 0 */", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 7: 0 */", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 10: 0 */", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 11: 11 */", "super"))); } @Test @@ -681,14 +681,14 @@ public void testClassAndMethodDeclaration_12() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 8: 0]", "extends Test"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "implements Serializable"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 11: 0]", "public TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 12: 12]", "super"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 0 */", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 7: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 9: 0 */", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 11: 0 */", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 12: 12 */", "super"))); } @Test @@ -712,14 +712,14 @@ public void testClassAndMethodDeclaration_14() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 1: 0]", "package org.jd.core.v1.service.writer;"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 3: 0]", "import java.util.ArrayList"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 4: 0]", "import org.junit.Assert"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 9: 0]", "public class TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 10: 0]", "extends Test"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 11: 0]", "implements Serializable"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 13: 0]", "public TokenWriterTest"))); - Assert.assertTrue(source.matches(PatternMaker.make("[ 14: 14]", "super"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 1: 0 */", "package org.jd.core.v1.service.writer;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "import java.util.ArrayList"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "import org.junit.Assert"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 9: 0 */", "public class TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 10: 0 */", "extends Test"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 11: 0 */", "implements Serializable"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 13: 0 */", "public TokenWriterTest"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 14: 14 */", "super"))); } @Test @@ -740,7 +740,7 @@ public void testLayout() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 22: 22]", "System", "println", "(i);"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 22: 22 */", "System", "println", "(i);"))); } @Test @@ -761,7 +761,7 @@ public void testLayoutWithoutLineNumber() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 15: 0]", "public Object", "nextElement"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 15: 0 */", "public Object", "nextElement"))); } @Test @@ -784,7 +784,7 @@ public void testLayoutWithStretchedfFragments_2() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 44: 44]") != -1); + Assert.assertTrue(source.indexOf("/* 44: 44 */") != -1); } @Test @@ -807,7 +807,7 @@ public void testLayoutWithStretchedfFragments_3() throws Exception { printSource(source); - Assert.assertTrue(source.indexOf("[ 66: 66]") != -1); + Assert.assertTrue(source.indexOf("/* 66: 66 */") != -1); } @Test @@ -830,7 +830,7 @@ public void testMoveDown() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 7: 0]", "public static void main"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 7: 0 */", "public static void main"))); } @Test @@ -853,7 +853,7 @@ public void testLinkedBlocks_16() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 16: 16]", "i = 4;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "i = 4;"))); } @Test @@ -876,7 +876,7 @@ public void testLinkedBlocks_22() throws Exception { printSource(source); - Assert.assertTrue(source.matches(PatternMaker.make("[ 22: 22]", "i = 4;"))); + Assert.assertTrue(source.matches(PatternMaker.make("/* 22: 22 */", "i = 4;"))); } /** @@ -1362,7 +1362,7 @@ public Message createSimpleMessage(int factor) { new DeclarationToken(DeclarationToken.METHOD, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), TextToken.LEFTROUNDBRACKET, new ReferenceToken(ReferenceToken.TYPE, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), - new TextToken("[] args)") + new TextToken("/*] args)") )); StartBodyFragment startMainMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); @@ -1637,7 +1637,7 @@ public Message createMessageToTestMoveDown() { new DeclarationToken(DeclarationToken.METHOD, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), TextToken.LEFTROUNDBRACKET, new ReferenceToken(ReferenceToken.TYPE, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), - new TextToken("[] args)") + new TextToken("/*] args)") )); StartBodyFragment startMainMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); @@ -1737,7 +1737,7 @@ public Message createMessageToTestLinkedBlocks(int lineNumber1, int lineNumber2, new DeclarationToken(DeclarationToken.METHOD, "org/jd/core/v1/service/test/TokenWriterTest", "main", "([Ljava/lang/String;)V"), TextToken.LEFTROUNDBRACKET, new ReferenceToken(ReferenceToken.TYPE, "java/lang/String", "String", null, "org/jd/core/v1/service/test/TokenWriterTest"), - new TextToken("[] args)") + new TextToken("/*] args)") )); StartBodyFragment startMainMethodBody = JavaFragmentFactory.addStartMethodBody(fragments); diff --git a/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java index 24a78a42..8098fd0e 100644 --- a/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -160,7 +160,7 @@ public void testClassDeclaration() throws Exception { System.out.print(source); System.out.println("- - - - - - - - "); - Assert.assertTrue(source.indexOf("[ 22: 22]") != -1); + Assert.assertTrue(source.indexOf("/* 22: 22 */") != -1); Assert.assertTrue(source.indexOf("java.lang.System") == -1); } @@ -186,7 +186,7 @@ public void testInterfaceDeclaration() throws Exception { message.setHeader("loader", new NopLoader()); message.setHeader("printer", printer); message.setHeader("maxLineNumber", 0); - message.setHeader("majorVersion", 0); + message.setHeader("majorVersion", 49); message.setHeader("minorVersion", 0); fragmenter.process(message); @@ -200,7 +200,7 @@ public void testInterfaceDeclaration() throws Exception { System.out.print(source); System.out.println("- - - - - - - - "); - Assert.assertTrue(source.indexOf("[ 1: 0] package org.jd.core.v1.service.test;") != -1); + Assert.assertTrue(source.indexOf("/* 1: 0 */ package org.jd.core.v1.service.test;") != -1); Assert.assertTrue(source.indexOf("interface InterfaceTest") != -1); Assert.assertTrue(source.indexOf("extends List") != -1); Assert.assertTrue(source.indexOf(";\n" + - "[ 4: 0] import static org.junit.Assert.*;\n" + - "[ 5: 0] \n" + - "[ 6: 0] public class WriteTokenTest {\n" + - "[ 7: 0] public static void main(String[] args) {\n" + - "[ 8: 8] if (args == null)\n" + - "[ 9: 0] return;\n" + - "[ 10: 10] int i = call(\n" + - "[ 11: 11] \"aaaa\",\n" + - "[ 12: 12] b,\n" + - "[ 13: 13] new Enumeration() {\n" + - "[ 14: 0] public boolean hasMoreElements() {\n" + - "[ 15: 15] return false;\n" + - "[ 16: 0] }\n" + - "[ 17: 0] public Object nextElement() {\n" + - "[ 18: 18] return null;\n" + - "[ 19: 0] }\n" + - "[ 20: 0] },\n" + - "[ 21: 21] c);\n" + - "[ 22: 22] System.out.println(i);\n" + - "[ 23: 0] }\n" + - "[ 24: 0] }\n"; + "/* 1: 0 */ package org.jd.core.v1.service.test;\n" + + "/* 2: 0 */ \n" + + "/* 3: 0 */ import java.util.ArrayList;\n" + + "/* 4: 0 */ import static org.junit.Assert.*;\n" + + "/* 5: 0 */ \n" + + "/* 6: 0 */ public class WriteTokenTest {\n" + + "/* 7: 0 */ public static void main(String[] args) {\n" + + "/* 8: 8 */ if (args == null)\n" + + "/* 9: 0 */ return;\n" + + "/* 10: 10 */ int i = call(\n" + + "/* 11: 11 */ \"aaaa\",\n" + + "/* 12: 12 */ b,\n" + + "/* 13: 13 */ new Enumeration() {\n" + + "/* 14: 0 */ public boolean hasMoreElements() {\n" + + "/* 15: 15 */ return false;\n" + + "/* 16: 0 */ }\n" + + "/* 17: 0 */ public Object nextElement() {\n" + + "/* 18: 18 */ return null;\n" + + "/* 19: 0 */ }\n" + + "/* 20: 0 */ },\n" + + "/* 21: 21 */ c);\n" + + "/* 22: 22 */ System.out.println(i);\n" + + "/* 23: 0 */ }\n" + + "/* 24: 0 */ }\n"; Assert.assertEquals(expected, source); } From 99c75c9423c01a3693f008566aa3f061e7373847 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 4 Aug 2019 22:42:24 +0200 Subject: [PATCH 052/211] Update local variable maker --- .../jd/core/v1/model/fragment/Fragment.java | 4 +- .../v1/model/javasyntax/type/GenericType.java | 29 +- .../v1/model/javasyntax/type/ObjectType.java | 9 +- .../model/javasyntax/type/PrimitiveType.java | 11 +- .../core/v1/model/javasyntax/type/Type.java | 6 +- .../statement/ClassFileTryStatement.java | 10 +- .../localvariable/AbstractLocalVariable.java | 155 +++++---- .../model/localvariable/Frame.java | 97 +++--- .../localvariable/GenericLocalVariable.java | 32 +- .../model/localvariable/LocalVariable.java | 19 -- .../model/localvariable/LocalVariableSet.java | 2 +- .../localvariable/ObjectLocalVariable.java | 314 ++++++------------ .../localvariable/PrimitiveLocalVariable.java | 211 +++++++----- .../util/ByteCodeParser.java | 251 ++++++++------ .../util/LocalVariableMaker.java | 194 +++-------- .../util/PrimitiveTypeUtil.java | 13 +- .../visitor/CreateInstructionsVisitor.java | 8 +- .../visitor/CreateLocalVariableVisitor.java | 12 +- .../GenerateParameterSuffixNameVisitor.java | 4 +- .../PopulateBlackListNamesVisitor.java | 4 +- .../visitor/TypeVisitor.java | 2 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 4 +- .../type/visitor/PrintTypeVisitor.java | 4 +- 23 files changed, 617 insertions(+), 778 deletions(-) delete mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java diff --git a/src/main/java/org/jd/core/v1/model/fragment/Fragment.java b/src/main/java/org/jd/core/v1/model/fragment/Fragment.java index a187300c..2a8c1d9d 100644 --- a/src/main/java/org/jd/core/v1/model/fragment/Fragment.java +++ b/src/main/java/org/jd/core/v1/model/fragment/Fragment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,7 +8,7 @@ package org.jd.core.v1.model.fragment; /** - * A fragment_OLD is a part of a concrete syntax tree. A fragment_OLD can be compacted, expanded and/or moved to match the + * A fragment is a part of a concrete syntax tree. A fragment can be compacted, expanded and/or moved to match the * original line numbers. * * @see FixedFragment diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java index a337abbc..1361e0c4 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,26 +8,27 @@ package org.jd.core.v1.model.javasyntax.type; public class GenericType implements Type { - protected String identifier; + protected String name; protected int dimension; - public GenericType(String identifier, int dimension) { - this.identifier = identifier; + public GenericType(String name, int dimension) { + this.name = name; this.dimension = dimension; } - public String getIdentifier() { - return identifier; + @Override + public String getName() { + return name; } @Override - public int getDimension() { - return dimension; + public String getDescriptor() { + return name; } @Override - public String getDescriptor() { - return identifier; + public int getDimension() { + return dimension; } @Override @@ -36,7 +37,7 @@ public Type createType(int dimension) { if (this.dimension == dimension) return this; else - return new GenericType(identifier, dimension); + return new GenericType(name, dimension); } @Override @@ -47,14 +48,14 @@ public boolean equals(Object o) { GenericType that = (GenericType) o; if (dimension != that.dimension) return false; - if (!identifier.equals(that.identifier)) return false; + if (!name.equals(that.name)) return false; return true; } @Override public int hashCode() { - int result = identifier.hashCode(); + int result = name.hashCode(); result = 31 * result + dimension; return result; } @@ -71,6 +72,6 @@ public boolean isGeneric() { @Override public String toString() { - return "GenericType{" + identifier + "}"; + return "GenericType{" + name + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index a1a9a95d..4c1bc166 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -88,6 +88,7 @@ public String getQualifiedName() { return qualifiedName; } + @Override public String getName() { return name; } @@ -97,13 +98,13 @@ public BaseTypeArgument getTypeArguments() { } @Override - public int getDimension() { - return dimension; + public String getDescriptor() { + return descriptor; } @Override - public String getDescriptor() { - return descriptor; + public int getDimension() { + return dimension; } @Override diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java index ab2372ad..f25ba239 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -90,8 +90,8 @@ else if ((flags & FLAG_SHORT) != 0) } @Override - public int getDimension() { - return dimension; + public String getName() { + return name; } @Override @@ -99,8 +99,9 @@ public String getDescriptor() { return descriptor; } - public String getName() { - return name; + @Override + public int getDimension() { + return dimension; } public int getFlags() { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java index 741f9702..5dd482f6 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,10 +8,12 @@ package org.jd.core.v1.model.javasyntax.type; public interface Type extends TypeArgument, BaseType, TypeBoundList { - int getDimension(); + String getName(); String getDescriptor(); + int getDimension(); + Type createType(int dimension); default boolean isPrimitive() { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java index f76d02da..a2da9a63 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -10,7 +10,7 @@ import org.jd.core.v1.model.javasyntax.statement.BaseStatement; import org.jd.core.v1.model.javasyntax.statement.TryStatement; import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.LocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import java.util.List; @@ -49,14 +49,14 @@ public boolean isEclipse() { } public static class CatchClause extends TryStatement.CatchClause { - protected LocalVariable localVariable; + protected AbstractLocalVariable localVariable; - public CatchClause(int lineNumber, ObjectType type, LocalVariable localVariable, BaseStatement statements) { + public CatchClause(int lineNumber, ObjectType type, AbstractLocalVariable localVariable, BaseStatement statements) { super(lineNumber, type, null, statements); this.localVariable = localVariable; } - public LocalVariable getLocalVariable() { + public AbstractLocalVariable getLocalVariable() { return localVariable; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java index ec4424d5..c29a56d7 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java @@ -8,10 +8,11 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.util.DefaultList; -public abstract class AbstractLocalVariable implements LocalVariable { +import java.util.HashSet; + +public abstract class AbstractLocalVariable { protected Frame frame; protected AbstractLocalVariable next; protected boolean declared; @@ -19,83 +20,41 @@ public abstract class AbstractLocalVariable implements LocalVariable { protected int fromOffset; protected int toOffset; protected String name; - protected int dimension; protected DefaultList references = new DefaultList<>(); + protected HashSet variablesOnRight = null; + protected HashSet variablesOnLeft = null; - public AbstractLocalVariable(int index, int offset, int dimension) { - this.declared = (offset == 0); - this.index = index; - this.fromOffset = offset; - this.toOffset = offset; - this.dimension = dimension; + public AbstractLocalVariable(int index, int offset, String name) { + this(index, offset, name, (offset == 0)); } - public AbstractLocalVariable(int index, int offset, int dimension, boolean declared) { + public AbstractLocalVariable(int index, int offset, String name, boolean declared) { this.declared = declared; this.index = index; this.fromOffset = offset; this.toOffset = offset; - this.dimension = dimension; - } - - public AbstractLocalVariable(int index, int offset, String name, int dimension) { - this.declared = (offset == 0); - this.index = index; - this.fromOffset = offset; - this.toOffset = offset; this.name = name; - this.dimension = dimension; } - public AbstractLocalVariable(int index, int offset, String name, int dimension, boolean declared) { - this.declared = declared; - this.index = index; - this.fromOffset = offset; - this.toOffset = offset; - this.name = name; - this.dimension = dimension; - } + public Frame getFrame() { return frame; } + public void setFrame(Frame frame) { this.frame = frame; } - public Frame getFrame() { - return frame; - } + public AbstractLocalVariable getNext() { return next; } + public void setNext(AbstractLocalVariable next) { this.next = next; } - public void setFrame(Frame frame) { - this.frame = frame; - } + public boolean isDeclared() { return declared; } + public void setDeclared(boolean declared) { this.declared = declared; } - public AbstractLocalVariable getNext() { - return next; - } + public int getIndex() { return index; } - public void setNext(AbstractLocalVariable next) { - this.next = next; - } - - public boolean isDeclared() { - return declared; - } - - public void setDeclared(boolean declared) { - this.declared = declared; - } - - public int getIndex() { - return index; - } - - public int getFromOffset() { - return fromOffset; - } + public int getFromOffset() { return fromOffset; } public void setFromOffset(int fromOffset) { assert fromOffset <= toOffset; this.fromOffset = fromOffset; } - public int getToOffset() { - return toOffset; - } + public int getToOffset() { return toOffset; } public void setToOffset(int offset) { if (this.fromOffset > offset) @@ -104,28 +63,62 @@ public void setToOffset(int offset) { this.toOffset = offset; } - @Override public String getName() { return name; } - - public void setName(String name) { - this.name = name; - } - - public int getDimension() { return dimension; } - - public DefaultList getReferences() { - return references; - } - - public abstract boolean isAssignable(Type otherType); - public abstract boolean isAssignable(AbstractLocalVariable other); - - public abstract void leftReduce(Type otherType); - public abstract void leftReduce(AbstractLocalVariable other); - - public abstract void rightReduce(Type otherType); - public abstract void rightReduce(AbstractLocalVariable other); - - public void addReference(LocalVariableReference reference) { - references.add(reference); + public abstract Type getType(); + + public String getName() { return name; } + public void setName(String name) { this.name = name; } + + public abstract int getDimension(); + + public abstract void accept(LocalVariableVisitor visitor); + + public DefaultList getReferences() { return references; } + public void addReference(LocalVariableReference reference) { references.add(reference); } + + /** + * Determines if the local variable represented by this object is either the same as, or is a super type variable + * of, the local variable represented by the specified parameter. + */ + public abstract boolean isAssignableFrom(Type type); + public abstract void typeOnRight(Type type); + public abstract void typeOnLeft(Type type); + + public abstract boolean isAssignableFrom(AbstractLocalVariable variable); + public abstract void variableOnRight(AbstractLocalVariable variable); + public abstract void variableOnLeft(AbstractLocalVariable variable); + + protected void fireChangeEvent() { + if (variablesOnLeft != null) { + for (AbstractLocalVariable v : variablesOnLeft) { + v.variableOnRight(this); + } + } + if (variablesOnRight != null) { + for (AbstractLocalVariable v : variablesOnRight) { + v.variableOnLeft(this); + } + } + } + + protected void addVariableOnLeft(AbstractLocalVariable variable) { + if (variablesOnLeft == null) { + variablesOnLeft = new HashSet<>(); + variablesOnLeft.add(variable); + variable.addVariableOnRight(this); + } else if (!variablesOnLeft.contains(variable)) { + variablesOnLeft.add(variable); + variable.addVariableOnRight(this); + } + } + + protected void addVariableOnRight(AbstractLocalVariable variable) { + if (variablesOnRight == null) { + variablesOnRight = new HashSet<>(); + variablesOnRight.add(variable); + variable.addVariableOnLeft(this); + } else if (!variablesOnRight.contains(variable)) { + variablesOnRight.add(variable); + variable.addVariableOnLeft(this); + } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 0c310215..71cbff9f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -105,20 +105,20 @@ public void mergeLocalVariable(AbstractLocalVariable lv) { lv.getReferences().addAll(alvToMerge.getReferences()); lv.setFromOffset(alvToMerge.getFromOffset()); - if (!lv.isAssignable(alvToMerge)) { + if (!lv.isAssignableFrom(alvToMerge)) { Type type = lv.getType(); Type alvToMergeType = alvToMerge.getType(); assert (type.isPrimitive() == alvToMergeType.isPrimitive()) && (type.isObject() == alvToMergeType.isObject()) && (type.isGeneric() == alvToMergeType.isGeneric()); if (type.isPrimitive()) { - if (alvToMerge.isAssignable(lv)) { + if (alvToMerge.isAssignableFrom(lv)) { ((PrimitiveLocalVariable)lv).setPrimitiveType((PrimitiveType)type); } else { ((PrimitiveLocalVariable)lv).setPrimitiveType(PrimitiveType.TYPE_INT); } } else if (type.isObject()) { - if (alvToMerge.isAssignable(lv)) { + if (alvToMerge.isAssignableFrom(lv)) { ((ObjectLocalVariable)lv).setObjectType((ObjectType)type); } else { ((ObjectLocalVariable)lv).setObjectType(ObjectType.TYPE_OBJECT); @@ -190,10 +190,10 @@ public void createNames(HashSet parentNames) { while (lv != null) { if (lv.name == null) { if (types.containsKey(lv.getType())) { - // Non unique lastType + // Non unique type types.put(lv.getType(), Boolean.TRUE); } else { - // Unique lastType + // Unique type types.put(lv.getType(), Boolean.FALSE); } } else { @@ -206,10 +206,10 @@ public void createNames(HashSet parentNames) { if (exceptionLocalVariable != null) { if (types.containsKey(exceptionLocalVariable.getType())) { - // Non unique lastType + // Non unique type types.put(exceptionLocalVariable.getType(), Boolean.TRUE); } else { - // Unique lastType + // Unique type types.put(exceptionLocalVariable.getType(), Boolean.FALSE); } } @@ -274,7 +274,7 @@ protected boolean createInlineDeclarations() { for (Map.Entry> entry : map.entrySet()) { Statements statements = entry.getKey().statements; ListIterator iterator = statements.listIterator(); - HashSet variablesToDeclare = entry.getValue(); + HashSet undeclaredLocalVariables = entry.getValue(); while (iterator.hasNext()) { Statement statement = iterator.next(); @@ -283,34 +283,34 @@ protected boolean createInlineDeclarations() { statement.accept(visitor); containsLineNumber |= visitor.containsLineNumber(); - HashSet foundVariables = visitor.getVariables(); - foundVariables.retainAll(variablesToDeclare); + HashSet undeclaredLocalVariablesInStatement = visitor.getVariables(); + undeclaredLocalVariablesInStatement.retainAll(undeclaredLocalVariables); - if (!foundVariables.isEmpty()) { + if (!undeclaredLocalVariablesInStatement.isEmpty()) { int index1 = iterator.nextIndex(); Class statementClass = statement.getClass(); if (statementClass == ExpressionStatement.class) { - createInlineDeclarations(variablesToDeclare, foundVariables, iterator, (ExpressionStatement)statement); + createInlineDeclarations(undeclaredLocalVariables, undeclaredLocalVariablesInStatement, iterator, (ExpressionStatement)statement); } else if (statementClass == ClassFileForStatement.class) { - createInlineDeclarations(variablesToDeclare, foundVariables, (ClassFileForStatement)statement); + createInlineDeclarations(undeclaredLocalVariables, undeclaredLocalVariablesInStatement, (ClassFileForStatement)statement); } - if (!foundVariables.isEmpty()) { + if (!undeclaredLocalVariablesInStatement.isEmpty()) { // Set the cursor before current statement - int index2 = iterator.nextIndex() + foundVariables.size(); + int index2 = iterator.nextIndex() + undeclaredLocalVariablesInStatement.size(); while (iterator.nextIndex() >= index1) { iterator.previous(); } - DefaultList sorted = new DefaultList<>(foundVariables); + DefaultList sorted = new DefaultList<>(undeclaredLocalVariablesInStatement); sorted.sort(ABSTRACT_LOCAL_VARIABLE_COMPARATOR); for (AbstractLocalVariable lv : sorted) { // Add declaration before current statement iterator.add(new LocalVariableDeclarationStatement(lv.getType(), new LocalVariableDeclarator(lv.getName()))); - variablesToDeclare.remove(lv); + undeclaredLocalVariables.remove(lv); } // Reset the cursor after current statement @@ -320,13 +320,13 @@ protected boolean createInlineDeclarations() { } } - if (variablesToDeclare.isEmpty()) { + if (undeclaredLocalVariables.isEmpty()) { break; } } - if (!variablesToDeclare.isEmpty()) { - DefaultList sorted = new DefaultList<>(variablesToDeclare); + if (!undeclaredLocalVariables.isEmpty()) { + DefaultList sorted = new DefaultList<>(undeclaredLocalVariables); sorted.sort(ABSTRACT_LOCAL_VARIABLE_COMPARATOR); for (AbstractLocalVariable lv : sorted) { @@ -369,7 +369,7 @@ protected HashMap> createMapForInlineDecla @SuppressWarnings("unchecked") protected void createInlineDeclarations( - HashSet variablesToDeclare, HashSet foundVariables, + HashSet undeclaredLocalVariables, HashSet undeclaredLocalVariablesInStatement, ListIterator iterator, ExpressionStatement es) { if (es.getExpression().getClass() == BinaryOperatorExpression.class) { @@ -378,35 +378,41 @@ protected void createInlineDeclarations( if (boe.getOperator().equals("=")) { Expressions expressions = new Expressions(); - splitMultiAssignment(Integer.MAX_VALUE, foundVariables, expressions, boe); + splitMultiAssignment(Integer.MAX_VALUE, undeclaredLocalVariablesInStatement, expressions, boe); iterator.remove(); for (BinaryOperatorExpression exp : (List)expressions) { - iterator.add(newDeclarationStatement(variablesToDeclare, foundVariables, exp)); + iterator.add(newDeclarationStatement(undeclaredLocalVariables, undeclaredLocalVariablesInStatement, exp)); } - if (expressions.isEmpty() || (expressions.getLast() != boe)) { + if (expressions.isEmpty()) { iterator.add(es); } } } } - protected Expression splitMultiAssignment(int toOffset, HashSet foundVariables, List expressions, Expression expression) { + protected Expression splitMultiAssignment( + int toOffset, HashSet undeclaredLocalVariablesInStatement, List expressions, Expression expression) { + if (expression.getClass() == BinaryOperatorExpression.class) { BinaryOperatorExpression boe = (BinaryOperatorExpression) expression; if (boe.getOperator().equals("=")) { - boe.setRightExpression(splitMultiAssignment(toOffset, foundVariables, expressions, boe.getRightExpression())); + Expression rightExpression = splitMultiAssignment(toOffset, undeclaredLocalVariablesInStatement, expressions, boe.getRightExpression()); if (boe.getLeftExpression().getClass() == ClassFileLocalVariableReferenceExpression.class) { ClassFileLocalVariableReferenceExpression lvre = (ClassFileLocalVariableReferenceExpression)boe.getLeftExpression(); AbstractLocalVariable localVariable = lvre.getLocalVariable(); - if (foundVariables.contains(localVariable) && (localVariable.getToOffset() <= toOffset)) { + if (undeclaredLocalVariablesInStatement.contains(localVariable) && (localVariable.getToOffset() <= toOffset)) { // Split multi assignment - expressions.add(boe); - // Insert declaration before + if (rightExpression == boe.getRightExpression()) { + expressions.add(boe); + } else { + expressions.add(new BinaryOperatorExpression(boe.getLineNumber(), boe.getType(), lvre, "=", rightExpression, boe.getPriority())); + } + // Return local variable return lvre; } } @@ -417,13 +423,13 @@ protected Expression splitMultiAssignment(int toOffset, HashSet variablesToDeclare, HashSet foundVariables, BinaryOperatorExpression boe) { + HashSet undeclaredLocalVariables, HashSet undeclaredLocalVariablesInStatement, BinaryOperatorExpression boe) { ClassFileLocalVariableReferenceExpression reference = (ClassFileLocalVariableReferenceExpression)boe.getLeftExpression(); AbstractLocalVariable localVariable = reference.getLocalVariable(); - variablesToDeclare.remove(localVariable); - foundVariables.remove(localVariable); + undeclaredLocalVariables.remove(localVariable); + undeclaredLocalVariablesInStatement.remove(localVariable); localVariable.setDeclared(true); Type type = localVariable.getType(); @@ -436,7 +442,7 @@ protected LocalVariableDeclarationStatement newDeclarationStatement( @SuppressWarnings("unchecked") protected void createInlineDeclarations( - HashSet variablesToDeclare, HashSet foundVariables, ClassFileForStatement fs) { + HashSet undeclaredLocalVariables, HashSet undeclaredLocalVariablesInStatement, ClassFileForStatement fs) { BaseExpression init = fs.getInit(); @@ -446,28 +452,29 @@ protected void createInlineDeclarations( if (init.isList()) { for (Expression exp : init.getList()) { - splitMultiAssignment(toOffset, foundVariables, expressions, exp); - if (expressions.isEmpty() || (expressions.getLast() != exp)) { + splitMultiAssignment(toOffset, undeclaredLocalVariablesInStatement, expressions, exp); + if (expressions.isEmpty()) { expressions.add(exp); } } } else { - splitMultiAssignment(toOffset, foundVariables, expressions, (Expression)init); - if (expressions.isEmpty() || (expressions.getLast() != init)) { + splitMultiAssignment(toOffset, undeclaredLocalVariablesInStatement, expressions, (Expression)init); + if (expressions.isEmpty()) { expressions.add(init.getFirst()); } } if (expressions.size() == 1) { - updateForStatement(variablesToDeclare, foundVariables, fs, expressions.getFirst()); + updateForStatement(undeclaredLocalVariables, undeclaredLocalVariablesInStatement, fs, expressions.getFirst()); } else { - updateForStatement(variablesToDeclare, foundVariables, fs, expressions); + updateForStatement(undeclaredLocalVariables, undeclaredLocalVariablesInStatement, fs, expressions); } } } protected void updateForStatement( - HashSet variablesToDeclare, HashSet foundVariables, ClassFileForStatement forStatement, Expression init) { + HashSet undeclaredLocalVariables, HashSet undeclaredLocalVariablesInStatement, + ClassFileForStatement forStatement, Expression init) { if (init.getClass() != BinaryOperatorExpression.class) return; @@ -483,8 +490,8 @@ protected void updateForStatement( if (localVariable.isDeclared() || (localVariable.getToOffset() > forStatement.getToOffset())) return; - variablesToDeclare.remove(localVariable); - foundVariables.remove(localVariable); + undeclaredLocalVariables.remove(localVariable); + undeclaredLocalVariablesInStatement.remove(localVariable); localVariable.setDeclared(true); VariableInitializer variableInitializer = (boe.getRightExpression().getClass() == NewInitializedArray.class) ? @@ -496,7 +503,9 @@ protected void updateForStatement( } @SuppressWarnings("unchecked") - protected void updateForStatement(HashSet variablesToDeclare, HashSet foundVariables, ClassFileForStatement forStatement, Expressions init) { + protected void updateForStatement( + HashSet variablesToDeclare, HashSet foundVariables, + ClassFileForStatement forStatement, Expressions init) { DefaultList boes = new DefaultList<>(); DefaultList localVariables = new DefaultList<>(); @@ -771,7 +780,7 @@ public void visit(InnerObjectType type) { @Override public void visit(GenericType type) { - visit(type, type.getIdentifier()); + visit(type, type.getName()); } protected void visit(Type type, String str) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java index 69523d60..473272af 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -13,13 +13,13 @@ public class GenericLocalVariable extends AbstractLocalVariable { protected GenericType type; - public GenericLocalVariable(int index, int offset, GenericType type, String name) { - super(index, offset, name, type.getDimension()); + public GenericLocalVariable(int index, int offset, GenericType type) { + super(index, offset, null); this.type = type; } - public GenericLocalVariable(int index, int offset, GenericType type) { - super(index, offset, type.getDimension()); + public GenericLocalVariable(int index, int offset, GenericType type, String name) { + super(index, offset, name); this.type = type; } @@ -28,19 +28,9 @@ public GenericType getType() { return type; } - @Override public void rightReduce(AbstractLocalVariable other) {} - @Override public void rightReduce(Type otherType) {} - @Override public void leftReduce(AbstractLocalVariable other) {} - @Override public void leftReduce(Type otherType) {} - - @Override - public boolean isAssignable(AbstractLocalVariable other) { - return true; - } - @Override - public boolean isAssignable(Type otherType) { - return true; + public int getDimension() { + return type.getDimension(); } @Override @@ -52,4 +42,12 @@ public void accept(LocalVariableVisitor visitor) { public String toString() { return "GenericLocalVariable{" + type + ", index=" + index + "}"; } + + @Override public boolean isAssignableFrom(Type otherType) { return true; } + @Override public void typeOnRight(Type type) {} + @Override public void typeOnLeft(Type type) {} + + @Override public boolean isAssignableFrom(AbstractLocalVariable variable) { return true; } + @Override public void variableOnRight(AbstractLocalVariable variable) {} + @Override public void variableOnLeft(AbstractLocalVariable variable) {} } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java deleted file mode 100644 index eecb5361..00000000 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariable.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2008, 2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; - -import org.jd.core.v1.model.javasyntax.type.Type; - - -public interface LocalVariable { - Type getType(); - - String getName(); - - void accept(LocalVariableVisitor visitor); -} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java index 93d00f2c..8a09b169 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/LocalVariableSet.java @@ -123,7 +123,7 @@ public void update(int index, int offset, ObjectType type) { while (lv != null) { if (lv.fromOffset == offset) { ObjectLocalVariable olv = (ObjectLocalVariable)lv; - olv.fromType = olv.toType = type; + olv.type = type; break; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 188a571a..6dc2afcd 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -8,239 +8,143 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import java.util.HashSet; + import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; public class ObjectLocalVariable extends AbstractLocalVariable { protected ObjectTypeMaker objectTypeMaker; - protected ObjectType fromType; - protected ObjectType toType; - protected Type arrayType; - - public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, ObjectType type, String name) { - super(index, offset, name, type.getDimension()); - this.objectTypeMaker = objectTypeMaker; - - if (dimension == 0) { - this.fromType = this.toType = type; - } else { - this.arrayType = type; - } - } + protected Type type; public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, Type type, String name) { - super(index, offset, name, type.getDimension()); + super(index, offset, name); this.objectTypeMaker = objectTypeMaker; - - if (dimension == 0) { - this.fromType = this.toType = (ObjectType)type; - } else { - this.arrayType = type; - } + this.type = type; } - public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, ObjectType type, String name, boolean declared) { - super(index, offset, name, type.getDimension(), declared); - this.objectTypeMaker = objectTypeMaker; - - if (dimension == 0) { - this.fromType = this.toType = type; - } else { - this.arrayType = type; - } - } - - public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, Type type) { - super(index, offset, type.getDimension()); - this.objectTypeMaker = objectTypeMaker; - - if (dimension == 0) { - this.fromType = this.toType = (ObjectType)type; - } else { - this.arrayType = type; - } + public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, Type type, String name, boolean declared) { + this(objectTypeMaker, index, offset, type, name); + this.declared = declared; } public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, ObjectLocalVariable objectLocalVariable) { - super(index, offset, objectLocalVariable.getDimension()); + super(index, offset, null); this.objectTypeMaker = objectTypeMaker; - this.toType = objectLocalVariable.toType; - this.arrayType = objectLocalVariable.arrayType; + this.type = objectLocalVariable.type; } @Override public Type getType() { - return (dimension == 0) ? toType : arrayType; + return type; } public void setObjectType(ObjectType type) { - dimension = type.getDimension(); - - if (dimension == 0) { - this.fromType = this.toType = (ObjectType)type; - } else { - this.arrayType = type; + if (!this.type.equals(type)) { + this.type = type; + fireChangeEvent(); } } @Override - public boolean isAssignable(AbstractLocalVariable other) { - if (other.getClass() == ObjectLocalVariable.class) { - if (toType == TYPE_UNDEFINED_OBJECT) { - return true; - } else if (dimension == other.getDimension()) { - ObjectLocalVariable olv = (ObjectLocalVariable) other; - - if (dimension == 0) { - if (olv.fromType == null) { - return isAssignable(olv.toType); - } else { - return isAssignable(olv.fromType); - } - } else { - return arrayType.equals(olv.arrayType); - } - } - } - - return false; + public int getDimension() { + return type.getDimension(); } @Override - public boolean isAssignable(Type otherType) { - if (otherType == TYPE_UNDEFINED_OBJECT) { - return true; - } - - if (toType == TYPE_UNDEFINED_OBJECT) { - return true; - } else if (dimension == otherType.getDimension()) { - if (dimension == 0) { - if (otherType.isObject()) { - return objectTypeMaker.isAssignable(toType, (ObjectType)otherType); - } - } else { - return arrayType.equals(otherType); - } - } - - return false; + public void accept(LocalVariableVisitor visitor) { + visitor.visit(this); } @Override - public void leftReduce(AbstractLocalVariable other) { - if (other.getClass() == ObjectLocalVariable.class) { - Type otherToType = ((ObjectLocalVariable) other).toType; - - if ((otherToType != null) && (otherToType != TYPE_UNDEFINED_OBJECT)) { - Type otherType = ((ObjectLocalVariable) other).fromType; + public String toString() { + StringBuilder sb = new StringBuilder(); - if (otherType == null) { - otherType = otherToType; - } + sb.append("ObjectLocalVariable{"); + sb.append(type.getName()); - if (toType == TYPE_UNDEFINED_OBJECT) { - leftReduce(otherType); - } else if ((dimension == 0) && (dimension == other.getDimension())) { - leftReduce(otherType); - } - } + if (type.getDimension() > 0) { + sb.append(new String(new char[type.getDimension()]).replaceAll("\0", "[]")); } - } - @Override - public void leftReduce(Type otherType) { - if (otherType != TYPE_UNDEFINED_OBJECT) { - if (toType == TYPE_UNDEFINED_OBJECT) { - if (otherType.getDimension() == 0) { - if (otherType.isObject()) { - fromType = toType = (ObjectType)otherType; - } - } else { - dimension = otherType.getDimension(); - arrayType = otherType; - } - } else if ((dimension == 0) && (otherType.getDimension() == 0) && otherType.isObject()) { - ObjectType otherObjectType = (ObjectType) otherType; + sb.append(' ').append(name).append(", index=").append(index); - if (toType.getInternalName().equals(otherObjectType.getInternalName()) || objectTypeMaker.isAssignable(otherObjectType, toType)) { - if (toType.getTypeArguments() == null) { - toType = otherObjectType; - } else if (otherObjectType.getTypeArguments() == null) { - toType = otherObjectType.createType(toType.getTypeArguments()); - } else if (toType.getTypeArguments().equals(otherObjectType.getTypeArguments())) { - toType = otherObjectType; - } - } - } + if (next != null) { + sb.append(", next=").append(next); } + + return sb.append("}").toString(); } @Override - public void rightReduce(AbstractLocalVariable other) { - if ((dimension == 0) && (other.getClass() == ObjectLocalVariable.class)) { - ObjectLocalVariable olv = (ObjectLocalVariable)other; - - if (toType == TYPE_UNDEFINED_OBJECT) { - dimension = olv.dimension; - fromType = olv.fromType; - toType = olv.toType; - } else { - assert (olv.getDimension() == 0); - - rightReduce(olv.toType); - } + public boolean isAssignableFrom(Type type) { + if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || this.type.equals(type)) { + return true; + } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0) && this.type.isObject() && type.isObject()) { + return objectTypeMaker.isAssignable((ObjectType)this.type, (ObjectType)type); } - } - @Override - public void rightReduce(Type otherType) { - if (dimension == 0) { - if (otherType.isObject()) { - if ((otherType != ObjectType.TYPE_OBJECT) && (otherType != TYPE_UNDEFINED_OBJECT)) { - if (toType == TYPE_UNDEFINED_OBJECT) { - dimension = otherType.getDimension(); + return false; + } - if (dimension == 0) { - fromType = null; - toType = (ObjectType) otherType; - } else { - arrayType = otherType; + public void typeOnRight(Type type) { + if (type != TYPE_UNDEFINED_OBJECT) { + if (this.type == TYPE_UNDEFINED_OBJECT) { + this.type = type; + fireChangeEvent(); + } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { + assert !this.type.isPrimitive() && !type.isPrimitive(); + + if (this.type.isObject() && type.isObject()) { + ObjectType thisObjectType = (ObjectType)this.type; + ObjectType otherObjectType = (ObjectType)type; + + if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = otherObjectType; + fireChangeEvent(); } - } else if (!otherType.equals(ObjectType.TYPE_OBJECT)) { - assert (otherType.getDimension() == 0) && otherType.isObject(); - - ObjectType otherObjectType = (ObjectType) otherType; - - if (fromType == null) { - if (toType.getTypeArguments() == null) { - fromType = otherObjectType; - } else if (otherObjectType.getTypeArguments() == null) { - fromType = otherObjectType.createType(toType.getTypeArguments()); - } else if (toType.getTypeArguments().equals(otherObjectType.getTypeArguments())) { - fromType = otherObjectType; - } - } else if (!fromType.getInternalName().equals(otherObjectType.getInternalName()) && objectTypeMaker.isAssignable(fromType, otherObjectType)) { - if (fromType.getTypeArguments() == null) { - fromType = otherObjectType; - } else if (otherObjectType.getTypeArguments() == null) { - fromType = otherObjectType.createType(fromType.getTypeArguments()); - } else if (fromType.getTypeArguments().equals(otherObjectType.getTypeArguments())) { - fromType = otherObjectType; - } + } else if (objectTypeMaker.isAssignable(thisObjectType, otherObjectType)) { + // Assignable types + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); + fireChangeEvent(); } } } - } else if (otherType.isPrimitive()) { - if (toType == TYPE_UNDEFINED_OBJECT) { - dimension = otherType.getDimension(); + } + } + } - if (dimension > 0) { - arrayType = otherType; - dimension = otherType.getDimension(); + public void typeOnLeft(Type type) { + if (type != TYPE_UNDEFINED_OBJECT) { + if (this.type == TYPE_UNDEFINED_OBJECT) { + this.type = type; + fireChangeEvent(); + } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { + assert !this.type.isPrimitive() && !type.isPrimitive(); + + if (this.type.isObject() && type.isObject()) { + ObjectType thisObjectType = (ObjectType)this.type; + ObjectType otherObjectType = (ObjectType)type; + + if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = otherObjectType; + fireChangeEvent(); + } + } else if (objectTypeMaker.isAssignable(otherObjectType, thisObjectType)) { + // Assignable types + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); + fireChangeEvent(); + } } } } @@ -248,43 +152,17 @@ public void rightReduce(Type otherType) { } @Override - public void accept(LocalVariableVisitor visitor) { - visitor.visit(this); + public boolean isAssignableFrom(AbstractLocalVariable variable) { + return isAssignableFrom(variable.getType()); } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append("ObjectLocalVariable{"); - - if (dimension == 0) { - if (fromType == null) { - sb.append('?'); - } else if (fromType.getQualifiedName() == null) { - sb.append(fromType.getName()); - } else { - sb.append(fromType.getQualifiedName()); - } - - if (!toType.equals(fromType)) { - sb.append(" ... "); - sb.append(toType.getQualifiedName()==null ? toType.getName() : toType.getQualifiedName()); - } - } else if (arrayType.isObject()){ - sb.append(((ObjectType)arrayType).getInternalName()); - sb.append(new String(new char[dimension]).replaceAll("\0", "[]")); - } else { - sb.append(((PrimitiveType)arrayType).getName()); - sb.append(new String(new char[dimension]).replaceAll("\0", "[]")); - } - - sb.append(' ').append(name).append(", index=").append(index); - - if (next != null) { - sb.append(", next=").append(next); - } + public void variableOnRight(AbstractLocalVariable variable) { + addVariableOnRight(variable); + typeOnRight(variable.getType()); + } - return sb.append("}").toString(); + public void variableOnLeft(AbstractLocalVariable variable) { + addVariableOnLeft(variable); + typeOnLeft(variable.getType()); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java index ec682a67..c2c2fde7 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -9,33 +9,22 @@ import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; + +import java.util.HashSet; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; public class PrimitiveLocalVariable extends AbstractLocalVariable { protected int flags; - public PrimitiveLocalVariable(int index, int offset, String descriptor, String name) { - super(index, offset, name, 0); - assert descriptor.charAt(0) != '['; - this.flags = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(descriptor).getFlags(); - } - public PrimitiveLocalVariable(int index, int offset, PrimitiveType type, String name) { - super(index, offset, name, 0); - assert type.getDimension() == 0; - this.flags = type.getFlags(); - } - - public PrimitiveLocalVariable(int index, int offset, PrimitiveType type) { - super(index, offset, 0); + super(index, offset, name); assert type.getDimension() == 0; this.flags = type.getFlags(); } public PrimitiveLocalVariable(int index, int offset, PrimitiveLocalVariable primitiveLocalVariable) { - super(index, offset, 0); + super(index, offset, null); assert primitiveLocalVariable.getDimension() == 0; int valueFlags = primitiveLocalVariable.flags; @@ -54,7 +43,48 @@ public PrimitiveLocalVariable(int index, int offset, PrimitiveLocalVariable prim @Override public Type getType() { - return PrimitiveTypeUtil.getPrimitiveType(flags, dimension); + switch (flags) { + case FLAG_BOOLEAN: + return TYPE_BOOLEAN; + case FLAG_CHAR: + return TYPE_CHAR; + case FLAG_FLOAT: + return TYPE_FLOAT; + case FLAG_DOUBLE: + return TYPE_DOUBLE; + case FLAG_BYTE: + return TYPE_BYTE; + case FLAG_SHORT: + return TYPE_SHORT; + case FLAG_INT: + return TYPE_INT; + case FLAG_LONG: + return TYPE_LONG; + case FLAG_VOID: + return TYPE_VOID; + } + + if (flags == (FLAG_CHAR|FLAG_INT)) + return MAYBE_CHAR_TYPE; + if (flags == (FLAG_CHAR|FLAG_SHORT|FLAG_INT)) + return MAYBE_SHORT_TYPE; + if (flags == (FLAG_BYTE|FLAG_CHAR|FLAG_SHORT|FLAG_INT)) + return MAYBE_BYTE_TYPE; + if (flags == (FLAG_BOOLEAN|FLAG_BYTE|FLAG_CHAR|FLAG_SHORT|FLAG_INT)) + return MAYBE_BOOLEAN_TYPE; + if (flags == (FLAG_BYTE|FLAG_SHORT|FLAG_INT)) + return MAYBE_NEGATIVE_BYTE_TYPE; + if (flags == (FLAG_SHORT|FLAG_INT)) + return MAYBE_NEGATIVE_SHORT_TYPE; + if (flags == (FLAG_BOOLEAN|FLAG_BYTE|FLAG_SHORT|FLAG_INT)) + return MAYBE_NEGATIVE_BOOLEAN_TYPE; + + return TYPE_INT; + } + + @Override + public int getDimension() { + return 0; } public void setPrimitiveType(PrimitiveType type) { @@ -63,115 +93,116 @@ public void setPrimitiveType(PrimitiveType type) { } @Override - public boolean isAssignable(AbstractLocalVariable other) { - if ((other.getDimension() == 0) && (other.getClass() == PrimitiveLocalVariable.class)) { - if (dimension == 0) { - return (flags & ((PrimitiveLocalVariable)other).flags) != 0; - } else { - return flags == ((PrimitiveLocalVariable)other).flags; - } + public void accept(LocalVariableVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("PrimitiveLocalVariable{"); + + if ((flags & FLAG_BOOLEAN) != 0) sb.append("boolean "); + if ((flags & FLAG_CHAR) != 0) sb.append("char "); + if ((flags & FLAG_FLOAT) != 0) sb.append("float "); + if ((flags & FLAG_DOUBLE) != 0) sb.append("double "); + if ((flags & FLAG_BYTE) != 0) sb.append("byte "); + if ((flags & FLAG_SHORT) != 0) sb.append("short "); + if ((flags & FLAG_INT) != 0) sb.append("int "); + if ((flags & FLAG_LONG) != 0) sb.append("long "); + if ((flags & FLAG_VOID) != 0) sb.append("void "); + + sb.append(name).append(", index=").append(index); + + if (next != null) { + sb.append(", next=").append(next); } - return false; + return sb.append("}").toString(); } @Override - public boolean isAssignable(Type otherType) { - if ((otherType.getDimension() == 0) && otherType.isPrimitive()) { - return (flags & ((PrimitiveType)otherType).getRightFlags()) != 0; + public boolean isAssignableFrom(Type type) { + if ((type.getDimension() == 0) && type.isPrimitive()) { + return (flags & ((PrimitiveType)type).getRightFlags()) != 0; } return false; } @Override - public void leftReduce(AbstractLocalVariable other) { - assert other.getDimension() == 0; + public void typeOnRight(Type type) { + assert (type.getDimension() == 0); - int otherFlags = ((PrimitiveLocalVariable)other).flags; - int newFalgs = 0; + int f = ((PrimitiveType)type).getRightFlags(); - if ((otherFlags & FLAG_BYTE) != 0) { - newFalgs |= FLAG_BYTE|FLAG_SHORT|FLAG_INT; - } - if ((otherFlags & FLAG_CHAR) != 0) { - newFalgs |= FLAG_CHAR|FLAG_INT; - } - if ((otherFlags & FLAG_SHORT) != 0) { - newFalgs |= FLAG_SHORT|FLAG_INT; - } - if ((otherFlags & FLAG_INT) != 0) { - newFalgs |= FLAG_INT; - } + if ((flags & f) != 0) { + int old = flags; + + flags &= f; - if ((flags & newFalgs) != 0) { - flags &= newFalgs; + if (old != flags) { + fireChangeEvent(); + } } } @Override - public void rightReduce(AbstractLocalVariable other) { - assert other.getDimension() == 0; + public void typeOnLeft(Type type) { + assert (type.getDimension() == 0); - int otherFlags = ((PrimitiveLocalVariable)other).flags; - int newFalgs = 0; + int f = ((PrimitiveType)type).getLeftFlags(); - if ((otherFlags & FLAG_INT) != 0) { - newFalgs |= FLAG_INT; - } - if ((otherFlags & FLAG_SHORT) != 0) { - newFalgs |= FLAG_SHORT|FLAG_BYTE; - } - if ((otherFlags & FLAG_CHAR) != 0) { - newFalgs |= FLAG_CHAR; - } - if ((otherFlags & FLAG_BYTE) != 0) { - newFalgs |= FLAG_BYTE; - } + if ((flags & f) != 0) { + int old = flags; - if ((flags & newFalgs) != 0) { - flags &= newFalgs; + flags &= f; + + if (old != flags) { + fireChangeEvent(); + } } } @Override - public void leftReduce(Type otherType) { - this.flags &= ((PrimitiveType)otherType).getRightFlags(); - assert (otherType.getDimension() == 0) && (this.flags != 0); - } + public boolean isAssignableFrom(AbstractLocalVariable variable) { + if (variable.getClass() == PrimitiveLocalVariable.class) { + return (flags & ((PrimitiveLocalVariable)variable).flags) != 0; + } - public void rightReduce(Type otherType) { - this.flags &= ((PrimitiveType)otherType).getLeftFlags(); - assert (otherType.getDimension() == 0) && (this.flags != 0) : "rightReduce : incompatible types"; + return false; } @Override - public void accept(LocalVariableVisitor visitor) { - visitor.visit(this); + public void variableOnRight(AbstractLocalVariable variable) { + assert variable.getDimension() == 0; + + addVariableOnRight(variable); + + int old = flags; + + flags &= ((PrimitiveLocalVariable)variable).flags; + assert flags != 0; + + if (old != flags) { + fireChangeEvent(); + } } @Override - public String toString() { - StringBuilder sb = new StringBuilder(); + public void variableOnLeft(AbstractLocalVariable variable) { + assert variable.getDimension() == 0; - sb.append("PrimitiveLocalVariable{"); + addVariableOnLeft(variable); - if ((flags & FLAG_BOOLEAN) != 0) sb.append("boolean "); - if ((flags & FLAG_CHAR) != 0) sb.append("char "); - if ((flags & FLAG_FLOAT) != 0) sb.append("float "); - if ((flags & FLAG_DOUBLE) != 0) sb.append("double "); - if ((flags & FLAG_BYTE) != 0) sb.append("byte "); - if ((flags & FLAG_SHORT) != 0) sb.append("short "); - if ((flags & FLAG_INT) != 0) sb.append("int "); - if ((flags & FLAG_LONG) != 0) sb.append("long "); - if ((flags & FLAG_VOID) != 0) sb.append("void "); + int old = flags; - sb.append(name).append(", index=").append(index); + flags &= ((PrimitiveLocalVariable)variable).flags; + assert flags != 0; - if (next != null) { - sb.append(", next=").append(next); + if (old != flags) { + fireChangeEvent(); } - - return sb.append("}").toString(); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index ce821203..611176dc 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -187,38 +187,31 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau stack.push(new ArrayExpression(lineNumber, arrayRef, indexRef)); break; case 54: case 55: case 56: case 57: // ISTORE, LSTORE, FSTORE, DSTORE - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(code[++offset] & 255, offset + 2, valueRef); + localVariable = getLocalVariableInAssignment(code[++offset] & 255, offset + 2, valueRef = stack.pop()); parseSTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 58: // ASTORE - valueRef = stack.pop(); - localVariable = localVariableMaker.getObjectLocalVariableInAssignment(code[++offset] & 255, offset + 1, valueRef); + localVariable = getLocalVariableInAssignment(code[++offset] & 255, offset + 1, valueRef = stack.pop()); parseASTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 59: case 60: case 61: case 62: // ISTORE_0 ... ISTORE_3 - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(opcode - 59, offset + 1, valueRef); + localVariable = getLocalVariableInAssignment(opcode - 59, offset + 1, valueRef = stack.pop()); parseSTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 63: case 64: case 65: case 66: // LSTORE_0 ... LSTORE_3 - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(opcode - 63, offset + 1, valueRef); + localVariable = getLocalVariableInAssignment(opcode - 63, offset + 1, valueRef = stack.pop()); parseSTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 67: case 68: case 69: case 70: // FSTORE_0 ... FSTORE_3 - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(opcode - 67, offset + 1, valueRef); + localVariable = getLocalVariableInAssignment(opcode - 67, offset + 1, valueRef = stack.pop()); parseSTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 71: case 72: case 73: case 74: // DSTORE_0 ... DSTORE_3 - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(opcode - 71, offset + 1, valueRef); + localVariable = getLocalVariableInAssignment(opcode - 71, offset + 1, valueRef = stack.pop()); parseSTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 75: case 76: case 77: case 78: // ASTORE_0 ... ASTORE_3 - valueRef = stack.pop(); - localVariable = localVariableMaker.getObjectLocalVariableInAssignment(opcode - 75, offset + 1, valueRef); + localVariable = getLocalVariableInAssignment(opcode - 75, offset + 1, valueRef = stack.pop()); parseASTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 79: // IASTORE @@ -403,7 +396,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 96: // IADD expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_BYTE_TYPE, expression1, "+", expression2, 6)); + stack.push(newIntegerBinaryOperatorExpression(lineNumber, expression1, "+", expression2, 6)); break; case 97: // LADD expression2 = stack.pop(); @@ -423,7 +416,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 100: // ISUB expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_BYTE_TYPE, expression1, "-", expression2, 6)); + stack.push(newIntegerBinaryOperatorExpression(lineNumber, expression1, "-", expression2, 6)); break; case 101: // LSUB expression2 = stack.pop(); @@ -443,7 +436,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 104: // IMUL expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_NEGATIVE_BYTE_TYPE, expression1, "*", expression2, 5)); + stack.push(newIntegerBinaryOperatorExpression(lineNumber, expression1, "*", expression2, 5)); break; case 105: // LMUL expression2 = stack.pop(); @@ -463,7 +456,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 108: // IDIV expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_NEGATIVE_BYTE_TYPE, expression1, "/", expression2, 5)); + stack.push(newIntegerBinaryOperatorExpression(lineNumber, expression1, "/", expression2, 5)); break; case 109: // LDIV expression2 = stack.pop(); @@ -483,7 +476,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 112: // IREM expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_NEGATIVE_BYTE_TYPE, expression1, "%", expression2, 5)); + stack.push(newIntegerBinaryOperatorExpression(lineNumber, expression1, "%", expression2, 5)); break; case 113: // LREM expression2 = stack.pop(); @@ -506,7 +499,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 120: // ISHL expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_BYTE_TYPE, expression1, "<<", expression2, 7)); + stack.push(newIntegerBinaryOperatorExpression(lineNumber, expression1, "<<", expression2, 7)); break; case 121: // LSHL expression2 = stack.pop(); @@ -516,7 +509,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 122: // ISHR expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_BYTE_TYPE, expression1, ">>", expression2, 7)); + stack.push(new BinaryOperatorExpression(lineNumber, TYPE_INT, expression1, ">>", expression2, 7)); break; case 123: // LSHR expression2 = stack.pop(); @@ -526,7 +519,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 124: // IUSHR expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_BYTE_TYPE, expression1, ">>>", expression2, 7)); + stack.push(newIntegerBinaryOperatorExpression(lineNumber, expression1, ">>>", expression2, 7)); break; case 125: // LUSHR expression2 = stack.pop(); @@ -536,7 +529,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 126: // IAND expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_BOOLEAN_TYPE, expression1, "&", expression2, 10)); + stack.push(newIntegerOrBooleanBinaryOperatorExpression(lineNumber, expression1, "&", expression2, 10)); break; case 127: // LAND expression2 = stack.pop(); @@ -546,7 +539,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 128: // IOR expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_BOOLEAN_TYPE, expression1, "|", expression2, 12)); + stack.push(newIntegerOrBooleanBinaryOperatorExpression(lineNumber, expression1, "|", expression2, 12)); break; case 129: // LOR expression2 = stack.pop(); @@ -556,7 +549,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 130: // IXOR expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newIntegerBinaryOperatorExpression(lineNumber, MAYBE_NEGATIVE_BOOLEAN_TYPE, expression1, "^", expression2, 11)); + stack.push(newIntegerOrBooleanBinaryOperatorExpression(lineNumber, expression1, "^", expression2, 11)); break; case 131: // LXOR expression2 = stack.pop(); @@ -645,38 +638,38 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 165: // IF_ACMPEQ expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "!=" : "==", expression2, 9)); + stack.push(newIntegerOrBooleanComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "!=" : "==", expression2, 9)); offset += 2; // Skip branch offset break; case 160: // IF_ICMPNE case 166: // IF_ACMPNE expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "==" : "!=", expression2, 9)); + stack.push(newIntegerOrBooleanComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "==" : "!=", expression2, 9)); offset += 2; // Skip branch offset break; case 161: // IF_ICMPLT expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">=" : "<", expression2, 8)); + stack.push(newIntegerComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">=" : "<", expression2, 8)); offset += 2; // Skip branch offset break; case 162: // IF_ICMPGE expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<" : ">=", expression2, 8)); + stack.push(newIntegerComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<" : ">=", expression2, 8)); offset += 2; // Skip branch offset break; case 163: // IF_ICMPGT expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<=" : ">", expression2, 8)); + stack.push(newIntegerComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? "<=" : ">", expression2, 8)); offset += 2; // Skip branch offset break; case 164: // IF_ICMPLE expression2 = stack.pop(); expression1 = stack.pop(); - stack.push(newNumericComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">" : "<=", expression2, 8)); + stack.push(newIntegerComparisonOperatorExpression(lineNumber, expression1, basicBlock.mustInverseCondition() ? ">" : "<=", expression2, 8)); offset += 2; // Skip branch offset break; case 168: // JSR @@ -860,28 +853,23 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau stack.push(new ClassFileLocalVariableReferenceExpression(lineNumber, localVariableMaker.getLocalVariable(i, offset))); break; case 54: // ISTORE - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(i, offset + 4, valueRef); + localVariable = getLocalVariableInAssignment(i, offset + 4, valueRef = stack.pop()); statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, localVariable.getType(), new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable), "=", valueRef, 16))); break; case 55: // LSTORE - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(i, offset + 4, valueRef); + localVariable = getLocalVariableInAssignment(i, offset + 4, valueRef = stack.pop()); statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, TYPE_LONG, new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable), "=", valueRef, 16))); break; case 56: // FSTORE - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(i, offset + 4, valueRef); + localVariable = getLocalVariableInAssignment(i, offset + 4, valueRef = stack.pop()); statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, TYPE_FLOAT, new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable), "=", valueRef, 16))); break; case 57: // DSTORE - valueRef = stack.pop(); - localVariable = localVariableMaker.getPrimitiveLocalVariableInAssignment(i, offset + 4, valueRef); + localVariable = getLocalVariableInAssignment(i, offset + 4, valueRef = stack.pop()); statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, TYPE_DOUBLE, new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable), "=", valueRef, 16))); break; case 58: // ASTORE - valueRef = stack.pop(); - localVariable = localVariableMaker.getObjectLocalVariableInAssignment(i, offset + 4, valueRef); + localVariable = getLocalVariableInAssignment(i, offset + 4, valueRef = stack.pop()); parseASTORE(statements, stack, lineNumber, localVariable, valueRef); break; case 169: // RET @@ -937,7 +925,9 @@ private BaseExpression getParameters(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, Constant constant) { switch (constant.getTag()) { case Constant.CONSTANT_Integer: @@ -1066,7 +1070,7 @@ private static void parseILOAD(Statements statements, DefaultStack Remove last statement and create a pre-incrementation + // IINC pattern found -> Remove last statement and create a pre-incrementation statements.removeLast(); stack.push(poe); return; @@ -1530,7 +1534,7 @@ private static void parseIINC(Statements statements, DefaultStack st ClassFileLocalVariableReferenceExpression exp = (ClassFileLocalVariableReferenceExpression)expression; if (exp.getLocalVariable() == localVariable) { - // Matching ILOAD found -> Create a post-incrementation + // ILOAD found -> Create a post-incrementation stack.pop(); if (count == 1) { @@ -1602,7 +1606,9 @@ private static void parseIF(DefaultStack stack, int lineNumber, Basi private void parseXRETURN(Statements statements, DefaultStack stack, int lineNumber) { Expression valueRef = stack.pop(); - localVariableMaker.updateTypeInReturn(valueRef); + if (valueRef.getClass() == ClassFileLocalVariableReferenceExpression.class) { + ((ClassFileLocalVariableReferenceExpression)valueRef).getLocalVariable().typeOnLeft(returnedType); + } if (valueRef.getClass() == NewArray.class) { valueRef = NewArrayMaker.make(statements, (NewArray)valueRef); @@ -1750,82 +1756,100 @@ private Expression newNewExpression(int lineNumber, String internalName) { return new NewExpression(lineNumber, objectType); } - private static Expression newIntegerBinaryOperatorExpression(int lineNumber, Type operatorConstraintType, Expression leftExpression, String operator, Expression rightExpression, int priority) { - Type leftType = leftExpression.getType(); - Type rightType = rightExpression.getType(); - Type type; + /* + * Operators = { "+", "-", "*", "/", "%", "<<", ">>", ">>>" } + * See "Additive Operators (+ and -) for Numeric Types": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2 + * See "Shift Operators": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19 + */ + private static Expression newIntegerBinaryOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + Class leftClass = leftExpression.getClass(); + Class rightClass = rightExpression.getClass(); - if (leftType == rightType) { - type = leftType; - } else { - type = PrimitiveTypeUtil.getCommonPrimitiveType((PrimitiveType)leftType, (PrimitiveType)rightType); - if (type == null) { - type = leftType; - } + if (leftClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable leftVariable = ((ClassFileLocalVariableReferenceExpression)leftExpression).getLocalVariable(); + + leftVariable.typeOnLeft(MAYBE_BYTE_TYPE); } - reduceIntegerLocalVariableType(leftExpression, rightExpression, operatorConstraintType); - reduceIntegerLocalVariableType(rightExpression, leftExpression, operatorConstraintType); + if (rightClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - return new BinaryOperatorExpression(lineNumber, type, leftExpression, operator, rightExpression, priority); + rightVariable.typeOnLeft(MAYBE_BYTE_TYPE); + } + + return new BinaryOperatorExpression(lineNumber, TYPE_INT, leftExpression, operator, rightExpression, priority); } - private static void reduceIntegerLocalVariableType(Expression expression1, Expression expression2, Type operatorConstraintType) { - if ((expression1.getClass() == ClassFileLocalVariableReferenceExpression.class) && (expression2.getClass() != IntegerConstantExpression.class)) { - ClassFileLocalVariableReferenceExpression lvre1 = (ClassFileLocalVariableReferenceExpression) expression1; + /* + * Operators = { "&", "|", "^" } + * See "Binary Numeric Promotion": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.22.1 + */ + private static Expression newIntegerOrBooleanBinaryOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + Class leftClass = leftExpression.getClass(); + Class rightClass = rightExpression.getClass(); + Type type = TYPE_INT; + + if (leftClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable leftVariable = ((ClassFileLocalVariableReferenceExpression)leftExpression).getLocalVariable(); - if (lvre1.getLocalVariable().getClass() == PrimitiveLocalVariable.class) { - PrimitiveLocalVariable plv1 = (PrimitiveLocalVariable) lvre1.getLocalVariable(); + if (rightClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - if (plv1.isAssignable(MAYBE_BOOLEAN_TYPE)) { - plv1.leftReduce(operatorConstraintType); - } + if (leftVariable.isAssignableFrom(TYPE_BOOLEAN) || rightVariable.isAssignableFrom(TYPE_BOOLEAN)) { + leftVariable.variableOnRight(rightVariable); + rightVariable.variableOnLeft(leftVariable); - if (expression2.getClass() == ClassFileLocalVariableReferenceExpression.class) { - ClassFileLocalVariableReferenceExpression lvre2 = (ClassFileLocalVariableReferenceExpression) expression2; - if (plv1.isAssignable(lvre2.getLocalVariable())) { - plv1.leftReduce(lvre2.getLocalVariable()); + if ((leftVariable.getType() == TYPE_BOOLEAN) || (rightVariable.getType() == TYPE_BOOLEAN)) { + type = TYPE_BOOLEAN; } - } else if (plv1.isAssignable(expression2.getType())) { - plv1.leftReduce(expression2.getType()); + } + } else { + if (rightExpression.getType() == TYPE_BOOLEAN) { + leftVariable.typeOnRight(type = TYPE_BOOLEAN); + } + } + } else { + if (rightClass == ClassFileLocalVariableReferenceExpression.class) { + if (leftExpression.getType() == TYPE_BOOLEAN) { + AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); + + rightVariable.typeOnRight(type = TYPE_BOOLEAN); } } } - } - private static Expression newComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { - return new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, leftExpression, operator, rightExpression, priority); + return new BinaryOperatorExpression(lineNumber, type, leftExpression, operator, rightExpression, priority); } - private static Expression newNumericComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { - Type leftType = leftExpression.getType(); - Type rightType = rightExpression.getType(); - Type type; + /* + * Operators = { "==", "!=" } + * See "Numerical Equality Operators == and !=": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.21.1 + */ + private static Expression newIntegerOrBooleanComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + Class leftClass = leftExpression.getClass(); + Class rightClass = rightExpression.getClass(); - if (leftType == rightType) { - type = leftType; - } else { - type = PrimitiveTypeUtil.getCommonPrimitiveType((PrimitiveType)leftType, (PrimitiveType)rightType); - if (type == null) { - type = leftType; - } - } + if (leftClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable leftVariable = ((ClassFileLocalVariableReferenceExpression)leftExpression).getLocalVariable(); - if ((((PrimitiveType)type).getFlags() & (FLAG_CHAR|FLAG_BYTE|FLAG_SHORT|FLAG_INT)) != 0) { - if (leftExpression.getClass() == ClassFileLocalVariableReferenceExpression.class) { - ClassFileLocalVariableReferenceExpression lvre = (ClassFileLocalVariableReferenceExpression) leftExpression; + if (rightClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - if (lvre.getLocalVariable().getClass() == PrimitiveLocalVariable.class) { - PrimitiveLocalVariable plv = (PrimitiveLocalVariable) lvre.getLocalVariable(); - plv.leftReduce(type); + if (leftVariable.isAssignableFrom(TYPE_BOOLEAN) || rightVariable.isAssignableFrom(TYPE_BOOLEAN)) { + leftVariable.variableOnRight(rightVariable); + rightVariable.variableOnLeft(leftVariable); + } + } else { + if (rightExpression.getType() == TYPE_BOOLEAN) { + leftVariable.typeOnRight(TYPE_BOOLEAN); } } - if (rightExpression.getClass() == ClassFileLocalVariableReferenceExpression.class) { - ClassFileLocalVariableReferenceExpression lvre = (ClassFileLocalVariableReferenceExpression) rightExpression; + } else { + if (rightClass == ClassFileLocalVariableReferenceExpression.class) { + if (leftExpression.getType() == TYPE_BOOLEAN) { + AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - if (lvre.getLocalVariable().getClass() == PrimitiveLocalVariable.class) { - PrimitiveLocalVariable plv = (PrimitiveLocalVariable) lvre.getLocalVariable(); - plv.leftReduce(type); + rightVariable.typeOnRight(TYPE_BOOLEAN); } } } @@ -1833,6 +1857,29 @@ private static Expression newNumericComparisonOperatorExpression(int lineNumber, return new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, leftExpression, operator, rightExpression, priority); } + /* + * Operators = { "==", "!=" } + * See "Numerical Equality Operators == and !=": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.21.1 + */ + private static Expression newIntegerComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + Class leftClass = leftExpression.getClass(); + Class rightClass = rightExpression.getClass(); + + if (leftClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable leftVariable = ((ClassFileLocalVariableReferenceExpression)leftExpression).getLocalVariable(); + + leftVariable.typeOnLeft(MAYBE_BYTE_TYPE); + } + + if (rightClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); + + rightVariable.typeOnLeft(MAYBE_BYTE_TYPE); + } + + return new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, leftExpression, operator, rightExpression, priority); + } + private static Expression newPreArithmeticOperatorExpression(int lineNumber, String operator, Expression expression) { reduceIntegerLocalVariableType(expression); return new PreOperatorExpression(lineNumber, operator, expression); @@ -1849,8 +1896,8 @@ private static void reduceIntegerLocalVariableType(Expression expression) { if (lvre.getLocalVariable().getClass() == PrimitiveLocalVariable.class) { PrimitiveLocalVariable plv = (PrimitiveLocalVariable)lvre.getLocalVariable(); - if (plv.isAssignable(MAYBE_BOOLEAN_TYPE)) { - plv.leftReduce(MAYBE_BYTE_TYPE); + if (plv.isAssignableFrom(MAYBE_BOOLEAN_TYPE)) { + plv.typeOnRight(MAYBE_BYTE_TYPE); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index c4c9c2f2..67479751 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -12,9 +12,7 @@ import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.model.classfile.attribute.*; import org.jd.core.v1.model.javasyntax.declaration.BaseFormalParameter; -import org.jd.core.v1.model.javasyntax.declaration.FormalParameter; import org.jd.core.v1.model.javasyntax.declaration.FormalParameters; -import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; import org.jd.core.v1.model.javasyntax.statement.Statements; import org.jd.core.v1.model.javasyntax.type.InnerObjectType; @@ -23,7 +21,6 @@ import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFormalParameter; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.*; @@ -45,13 +42,11 @@ public class LocalVariableMaker { protected FormalParameters formalParameters; protected PopulateBlackListNamesVisitor populateBlackListNamesVisitor = new PopulateBlackListNamesVisitor(blackListNames); - protected UpdateTypeInParameterVisitor updateTypeInParameterVisitor = new UpdateTypeInParameterVisitor(); protected CreateParameterVisitor createParameterVisitor; protected CreateLocalVariableVisitor createLocalVariableVisitor; - protected UpdateTypeInReturnVisitor updateTypeInReturnVisitor; @SuppressWarnings("unchecked") - public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, ClassFileConstructorOrMethodDeclaration comdwln, boolean constructor, List parameterTypes, Type returnedType) { + public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, ClassFileConstructorOrMethodDeclaration comdwln, boolean constructor, List parameterTypes) { ClassFile classFile = comdwln.getClassFile(); Method method = comdwln.getMethod(); @@ -59,7 +54,6 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa this.signatureParser = signatureParser; this.createParameterVisitor = new CreateParameterVisitor(objectTypeMaker); this.createLocalVariableVisitor = new CreateLocalVariableVisitor(objectTypeMaker); - this.updateTypeInReturnVisitor = new UpdateTypeInReturnVisitor(returnedType); // Initialize local black list variable names if (classFile.getFields() != null) { @@ -198,7 +192,7 @@ protected void initLocalVariablesFromAttributes(Method method) { int dimension = SignatureParser.countDimension(descriptor); if (dimension == 0) { - lv = new PrimitiveLocalVariable(index, startPc, descriptor, name); + lv = new PrimitiveLocalVariable(index, startPc, PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(descriptor), name); } else { lv = new ObjectLocalVariable(objectTypeMaker, index, startPc, signatureParser.parseTypeSignature(descriptor.substring(dimension)).createType(dimension), name); } @@ -228,12 +222,7 @@ protected void initLocalVariablesFromParameterTypes(ClassFile classFile, List Create a new local variable - createLocalVariableVisitor.init(index, offset); - valuePrimitiveLocalVariable.accept(createLocalVariableVisitor); - lv = createLocalVariableVisitor.getLocalVariable(); - } - } else { - Type valueType = value.getType(); - - if (lv.isAssignable(valueType)) { - // Reduce lastType flags - lv.leftReduce(valueType); - } else { - // Not assignable -> Create a new local variable - createLocalVariableVisitor.init(index, offset); - valueType.accept(createLocalVariableVisitor); - lv = createLocalVariableVisitor.getLocalVariable(); - } - } + } else if (lv.isAssignableFrom(valueType)) { + // Reduce type + lv.typeOnRight(valueType); + } else { + // Not assignable -> Create a new local variable + createLocalVariableVisitor.init(index, offset); + valueType.accept(createLocalVariableVisitor); + lv = createLocalVariableVisitor.getLocalVariable(); + } lv.setToOffset(offset); store(lv); @@ -387,77 +359,47 @@ public AbstractLocalVariable getPrimitiveLocalVariableInAssignment(int index, in return lv; } - public AbstractLocalVariable getObjectLocalVariableInAssignment(int index, int offset, Expression value) { - AbstractLocalVariable lv = localVariableSet.get(index, offset); - Class valueClass = value.getClass(); + public AbstractLocalVariable getLocalVariableInNullAssignment(int index, int offset, Type valueType) { + AbstractLocalVariable lv = searchLocalVariable(index, offset); if (lv == null) { - lv = currentFrame.getLocalVariable(index); + // Create a new local variable + createLocalVariableVisitor.init(index, offset); + valueType.accept(createLocalVariableVisitor); + lv = createLocalVariableVisitor.getLocalVariable(); } else { - AbstractLocalVariable lv2 = currentFrame.getLocalVariable(index); + Type type = lv.getType(); - if ((lv2 != null) && (lv.getFromOffset() < lv2.getFromOffset())) { - lv = lv2; - } else { - localVariableSet.remove(index, offset); + if ((type.getDimension() == 0) && type.isPrimitive()) { + // Not assignable -> Create a new local variable + createLocalVariableVisitor.init(index, offset); + valueType.accept(createLocalVariableVisitor); + lv = createLocalVariableVisitor.getLocalVariable(); } } + lv.setToOffset(offset); + store(lv); + + return lv; + } + + public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, AbstractLocalVariable valueLocalVariable) { + AbstractLocalVariable lv = searchLocalVariable(index, offset); + if (lv == null) { // Create a new local variable createLocalVariableVisitor.init(index, offset); - - if (valueClass == ClassFileLocalVariableReferenceExpression.class) { - ((ClassFileLocalVariableReferenceExpression) value).getLocalVariable().accept(createLocalVariableVisitor); - } else { - value.getType().accept(createLocalVariableVisitor); - } - + valueLocalVariable.accept(createLocalVariableVisitor); + lv = createLocalVariableVisitor.getLocalVariable(); + } else if (!lv.isAssignableFrom(valueLocalVariable)) { + // Not assignable -> Create a new local variable + createLocalVariableVisitor.init(index, offset); + valueLocalVariable.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); - } else { - if (valueClass == ClassFileLocalVariableReferenceExpression.class) { - AbstractLocalVariable alv = ((ClassFileLocalVariableReferenceExpression)value).getLocalVariable(); - - if (lv.isAssignable(alv)) { - // Reduce lastType range - lv.leftReduce(alv); - alv.rightReduce(lv); - } else { - // Non-compatible types -> Create a new local variable - createLocalVariableVisitor.init(index, offset); - alv.accept(createLocalVariableVisitor); - lv = createLocalVariableVisitor.getLocalVariable(); - } - } else if (valueClass == NullExpression.class) { - Type type = lv.getType(); - - if ((type.getDimension() == 0) && type.isPrimitive()) { - // Not assignable -> Create a new local variable - createLocalVariableVisitor.init(index, offset); - value.getType().accept(createLocalVariableVisitor); - lv = createLocalVariableVisitor.getLocalVariable(); - } else { - ((NullExpression)value).setType(lv.getType()); - } - } else { - Type valueType = value.getType(); - - if (lv.isAssignable(valueType)) { - // Reduce lastType range - lv.leftReduce(valueType); - } else { - // Not assignable -> Create a new local variable - createLocalVariableVisitor.init(index, offset); - valueType.accept(createLocalVariableVisitor); - lv = createLocalVariableVisitor.getLocalVariable(); - } - - if (valueClass == NewExpression.class) { - currentFrame.addNewExpression((NewExpression)value, lv); - } - } } + lv.variableOnRight(valueLocalVariable); lv.setToOffset(offset); store(lv); @@ -484,15 +426,6 @@ public AbstractLocalVariable getExceptionLocalVariable(int index, int offset, Ob return lv; } - public void updateTypeInParameter(Expression expression, Type type) { - updateTypeInParameterVisitor.setType(type); - expression.accept(updateTypeInParameterVisitor); - } - - public void updateTypeInReturn(Expression expression) { - expression.accept(updateTypeInReturnVisitor); - } - public void removeLocalVariable(AbstractLocalVariable lv) { int index = lv.getIndex(); @@ -555,37 +488,12 @@ protected Frame searchCommonParentFrame(Frame frame1, Frame frame2) { } while (frame2 != null) { - if (set.contains(frame2)) + if (set.contains(frame2)) { return frame2; + } frame2 = frame2.getParent(); } return null; } - - protected static class UpdateTypeInParameterVisitor extends AbstractNopExpressionVisitor { - protected Type type; - - public void setType(Type type) { - this.type = type; - } - - @Override - public void visit(LocalVariableReferenceExpression expression) { - (((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable()).rightReduce(type); - } - } - - protected static class UpdateTypeInReturnVisitor extends AbstractNopExpressionVisitor { - protected Type returnedType; - - public UpdateTypeInReturnVisitor(Type returnedType) { - this.returnedType = returnedType; - } - - @Override - public void visit(LocalVariableReferenceExpression expression) { - (((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable()).rightReduce(returnedType); - } - } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java index 1afbe79d..f62f4a22 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -67,17 +67,6 @@ else if ((flags & FLAG_SHORT) != 0) return flags; } - public static PrimitiveType getPrimitiveType(int flags, int dimension) { - PrimitiveType type = getPrimitiveType(flags); - - if (type == null) { - type = TYPE_INT; - } - - return type.createType(dimension); - } - - public static PrimitiveType getCommonPrimitiveType(PrimitiveType pt1, PrimitiveType pt2) { assert (pt1.getDimension() == 0) && (pt2.getDimension() == 0); return getPrimitiveType(pt1.getFlags() & pt2.getFlags()); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java index 4f1bc31a..270b8d99 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -81,7 +81,7 @@ public void visit(FieldDeclaration declaration) {} @Override public void visit(ConstructorDeclaration declaration) { ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, true, comdwln.getParameterTypes(), null); + LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, true, comdwln.getParameterTypes()); createParametersVariablesAndStatements(comdwln, localVariableMaker); } @@ -89,7 +89,7 @@ public void visit(ConstructorDeclaration declaration) { @Override public void visit(MethodDeclaration declaration) { ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, false, comdwln.getParameterTypes(), comdwln.getReturnedType()); + LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, false, comdwln.getParameterTypes()); createParametersVariablesAndStatements(comdwln, localVariableMaker); } @@ -97,7 +97,7 @@ public void visit(MethodDeclaration declaration) { @Override public void visit(StaticInitializerDeclaration declaration) { ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, false, null, null); + LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, false, null); createParametersVariablesAndStatements(comdwln, localVariableMaker); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java index 41a28c9e..a2b499e8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -34,20 +34,20 @@ public AbstractLocalVariable getLocalVariable() { @Override public void visit(PrimitiveType type) { if (type.getDimension() == 0) { - localVariable = new PrimitiveLocalVariable(index, offset, type); + localVariable = new PrimitiveLocalVariable(index, offset, type, null); } else { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type); + localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null); } } @Override public void visit(ObjectType type) { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type); + localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null); } @Override public void visit(InnerObjectType type) { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type); + localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null); } @Override @@ -70,7 +70,7 @@ public void visit(PrimitiveLocalVariable lv) { if (lv.getDimension() == 0) { localVariable = new PrimitiveLocalVariable(index, offset, lv); } else { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, lv.getType()); + localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, lv.getType(), null); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java index a923413d..8588694f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -46,6 +46,6 @@ public void visit(InnerObjectType type) { @Override public void visit(GenericType type) { - suffix = type.getIdentifier(); + suffix = type.getName(); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java index 675e5442..5cde68e8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -33,6 +33,6 @@ public void visit(InnerObjectType type) { @Override public void visit(GenericType type) { - blackListNames.add(type.getIdentifier()); + blackListNames.add(type.getName()); } } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index f32b293a..b279d149 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -205,7 +205,7 @@ public void visit(TypeParameters list) { @Override public void visit(GenericType type) { - tokens.add(newTextToken(type.getIdentifier())); + tokens.add(newTextToken(type.getName())); visitDimension(type.getDimension()); } diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 319b0f2e..0c4a48ca 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -762,7 +762,7 @@ public void testJdk170NoDebugFor() throws Exception { assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors - // TODO: fix error on line 168. assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + //assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @Test @@ -806,7 +806,7 @@ public void testJdk150For() throws Exception { assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors - // TODO: fix error on line 205. assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @Test diff --git a/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java index d85b998f..5a43e307 100644 --- a/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java +++ b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -117,7 +117,7 @@ public void visit(TypeParameters types) { } @Override public void visit(GenericType type) { - sb.append(type.getIdentifier()); + sb.append(type.getName()); printDimension(type.getDimension()); } From 85f35bbb4db15cf31538c927b27c2ee71682d228 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 4 Aug 2019 23:24:00 +0200 Subject: [PATCH 053/211] Add tests --- .../jd/core/v1/ClassFileToJavaSourceTest.java | 80 +++++++++--------- .../core/v1/LayoutFragmentProcessorTest.java | 2 +- .../java/org/jd/core/test/Basic.java | 6 +- ...data-java-eclipse-java-compiler-3.13.0.zip | Bin 37354 -> 38140 bytes .../resources/zip/data-java-ibm-j9_vm.zip | Bin 44297 -> 44420 bytes .../resources/zip/data-java-jdk-1.1.8.zip | Bin 23764 -> 23872 bytes .../resources/zip/data-java-jdk-1.3.1.zip | Bin 21620 -> 21734 bytes .../resources/zip/data-java-jdk-1.4.2.zip | Bin 22116 -> 22177 bytes .../resources/zip/data-java-jdk-1.5.0.zip | Bin 39805 -> 39848 bytes .../resources/zip/data-java-jdk-1.6.0.zip | Bin 55695 -> 55749 bytes .../zip/data-java-jdk-1.7.0-no-debug-info.zip | Bin 7885 -> 7934 bytes .../resources/zip/data-java-jdk-1.7.0.zip | Bin 64576 -> 64633 bytes .../resources/zip/data-java-jdk-1.8.0.zip | Bin 67546 -> 67600 bytes .../resources/zip/data-java-jdk-10.0.2.zip | Bin 21468 -> 21529 bytes .../resources/zip/data-java-jdk-9.0.1.zip | Bin 21451 -> 21514 bytes 15 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 0c4a48ca..97cb1c80 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -80,42 +80,42 @@ public void testJdk170Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("int j = 1, k[] = {1, l[][] = {"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); - assertTrue(source.matches(PatternMaker.make(": 58 */", "return new String[] {s, s + '?'};"))); + assertTrue(source.matches(PatternMaker.make(": 60 */", "return new String[] {s, s + '?'};"))); assertTrue(source.indexOf("if (this instanceof Object)") != -1); assertTrue(source.indexOf("int k = 50 / (25 + (i = 789));") != -1); - assertTrue(source.matches(PatternMaker.make(": 80 */", "k = i += 100;"))); - assertTrue(source.matches(PatternMaker.make(": 85 */", "i = ++this.int78;"))); - assertTrue(source.matches(PatternMaker.make(": 86 */", "i = this.int78++;"))); - assertTrue(source.matches(PatternMaker.make(": 87 */", "i *= 10;"))); - assertTrue(source.matches(PatternMaker.make(": 89 */", "this.int78 = ++i;"))); - assertTrue(source.matches(PatternMaker.make(": 90 */", "this.int78 = i++;"))); - assertTrue(source.matches(PatternMaker.make(": 91 */", "this.int78 *= 10;"))); - assertTrue(source.matches(PatternMaker.make(": 93 */", "long34 = ++long12;"))); - assertTrue(source.matches(PatternMaker.make(": 94 */", "long34 = long12++;"))); - assertTrue(source.matches(PatternMaker.make(": 95 */", "long34 *= 10L;"))); - assertTrue(source.matches(PatternMaker.make(": 97 */", "i = (int)long12 + this.int78;"))); - assertTrue(source.matches(PatternMaker.make(": 99 */", "i = k ^ 0xFF;"))); - assertTrue(source.matches(PatternMaker.make(": 100 */", "i |= 0x7;"))); + assertTrue(source.matches(PatternMaker.make(": 82 */", "k = i += 100;"))); + assertTrue(source.matches(PatternMaker.make(": 87 */", "i = ++this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "i = this.int78++;"))); + assertTrue(source.matches(PatternMaker.make(": 89 */", "i *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 91 */", "this.int78 = ++i;"))); + assertTrue(source.matches(PatternMaker.make(": 92 */", "this.int78 = i++;"))); + assertTrue(source.matches(PatternMaker.make(": 93 */", "this.int78 *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 95 */", "long34 = ++long12;"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "long34 = long12++;"))); + assertTrue(source.matches(PatternMaker.make(": 97 */", "long34 *= 10L;"))); + assertTrue(source.matches(PatternMaker.make(": 99 */", "i = (int)long12 + this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 101 */", "i = k ^ 0xFF;"))); + assertTrue(source.matches(PatternMaker.make(": 102 */", "i |= 0x7;"))); assertTrue(source.indexOf("int result;") != -1); - assertTrue(source.matches(PatternMaker.make(": 112 */", "result = 1;"))); - assertTrue(source.matches(PatternMaker.make(": 114 */", "int k = i;"))); - assertTrue(source.matches(PatternMaker.make(": 115 */", "result = k + 2;"))); - assertTrue(source.matches(PatternMaker.make(": 118 */", "result = this.short56;"))); - assertTrue(source.matches(PatternMaker.make(": 122 */", "return result;"))); - assertTrue(source.matches(PatternMaker.make(": 126 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); - assertTrue(source.matches(PatternMaker.make(": 128 */", "i = (int)(Basic.long12 + long12) + this.int78 + int78;"))); + assertTrue(source.matches(PatternMaker.make(": 114 */", "result = 1;"))); + assertTrue(source.matches(PatternMaker.make(": 116 */", "int k = i;"))); + assertTrue(source.matches(PatternMaker.make(": 117 */", "result = k + 2;"))); + assertTrue(source.matches(PatternMaker.make(": 120 */", "result = this.short56;"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "return result;"))); + assertTrue(source.matches(PatternMaker.make(": 128 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make(": 130 */", "i = (int)(Basic.long12 + long12) + this.int78 + int78;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("()") == -1); assertTrue(source.indexOf("NaND") == -1); @@ -2396,9 +2396,9 @@ public void testJdk118Basic() throws Exception { assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make(": 126 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); - assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return String.valueOf(str) + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make(": 128 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return String.valueOf(str) + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -2438,10 +2438,10 @@ public void testJdk142Basic() throws Exception { assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -2481,10 +2481,10 @@ public void testJdk901Basic() throws Exception { assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -2524,10 +2524,10 @@ public void testJdk1002Basic() throws Exception { assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("/* 171: 171 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 174: 174 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("/* 183: 183 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("/* 186: 186 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); assertTrue(source.indexOf("// Byte code:") == -1); diff --git a/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java b/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java index 5a8d4697..ca8bcc05 100644 --- a/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java +++ b/src/test/java/org/jd/core/v1/LayoutFragmentProcessorTest.java @@ -60,7 +60,7 @@ public void testJdk118Basic() throws Exception { printSource(source); - assertTrue(source.indexOf("/* 183: 183 */") != -1); + assertTrue(source.indexOf("/* 188: 188 */") != -1); } @Test diff --git a/src/test/resources/java/org/jd/core/test/Basic.java b/src/test/resources/java/org/jd/core/test/Basic.java index 4afda88f..32910815 100644 --- a/src/test/resources/java/org/jd/core/test/Basic.java +++ b/src/test/resources/java/org/jd/core/test/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -27,7 +27,7 @@ public void printHelloWorld() { System.out.println("world"); } - public void declarations(int i) { + public void declarations(int i, long long12) { String str1 = "3 == " + (i+1) + " ?"; String str2 = str1.valueOf("abc \b \f \n \r \t \" \007 def"); @@ -52,6 +52,8 @@ public void declarations(int i) { int j = 1, k[] = { 1 }, l[][] = {{ 1 }, { 2 }, {}}; String stringNull = null; + + System.out.println("static long12 = " + Basic.long12); } public String[] createStringArray(String s) { diff --git a/src/test/resources/zip/data-java-eclipse-java-compiler-3.13.0.zip b/src/test/resources/zip/data-java-eclipse-java-compiler-3.13.0.zip index a3ba4aa581421e1b324d611e9bac3425cfca61ee..b79d9d12f4be68167c476fd977544b9b0abb9085 100644 GIT binary patch delta 2659 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 RO#W%=Khi%-Dxv$k{souhT~Gi3 diff --git a/src/test/resources/zip/data-java-jdk-1.1.8.zip b/src/test/resources/zip/data-java-jdk-1.1.8.zip index 5c3618875a4f11299325b9a1ee8ff7ed9aa92e48..56b12ebe8fba46e0edf7057fcba8e35488096618 100644 GIT binary patch delta 3052 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 diff --git a/src/test/resources/zip/data-java-jdk-1.3.1.zip b/src/test/resources/zip/data-java-jdk-1.3.1.zip index a24e9b775b74d2315e0f953873d37751dfe96077..aa3285bc0d10e6538aea1e7cf966c3bd2a6ff673 100644 GIT binary patch delta 3001 zcmV;q3r6(xr~&4w0kF6Q4nVjBPX;dX((VcX0P7QzutFD;-31PRSR6$Z{+DaZW|iYO zf(q&-Mspl01`H|!77`Uiq7s8A7B0sE7mr)qTQsrv-n+3^>_#yJOYFV(-h1!8|1*1c zLBImv&Agp?^U6Q}d%KVPaqAs$VLipG;d+>Yfc?$B^2?ox5L5BF#MUaiupb<+^^yRF+Zr{A#w6y4Ugba zar`kAk87Nt@Zm`nPpNoXJU!#XAu65~3eSmi&x_#&6)*bml8TpAydt(<^}zYlvci7i z@M~gtU7UDBV{C7F5Bl;?`KRJ7;rtC1Z~O30_Kcntrg}Gj&!6(^+*#|bB8)hE}&)#v5s+ltt6tygf?H#L3 z#!@|%O)1;xF|17$OpYgG>GU+QHBD?yYqPCHsz*WLDD_66L*@LoMJc=2uoH1cT9-&A z>;?s{aQQq1?nbkVaTK&9Qby}Q-+aTG8=IfxN}$Dmj1!5Nl@QOFMYr9XNGn*S#k6`V z7j#v|P0OgXjkI04Wh|YDZ%RY`7E{{BNG8p8(@J(J(7O!AYQ=0K%CnwuQ?qcaBxo*e zTQh{K6(KumZ0hV)5v}+P>NW~NK2?ihL#83~pOF=+vO;xM$mz_?3N>^dvwFm#qK@${ zGrLuPbhm)NJ?W^Ui9(W4bqGmIOU2fKB$o=~mJzcJ=j;}i6| z*=F_`cCWm)jl$#ZZGw~K6I`x`$?dx@0Tac_tR8X<_JEaY zA-UyJGYR1=%`ykbDY?jEC?17Id&2I`(s`W;Fr6?w7jK7=^cZ$aEX{=03y;Qc∈N z+~&!DB(BetDnzhof`bHzmYbYvE}6)5n}pM;N(F0&|KH{1E!;p1q~z4GyRD|Zl{t`q z>YBYUZuE=d5kb_&lbQ0>+ROnfZfunh7-}+$^@Rl=KGpFV1{H+<%bB6Y5DNEjxTVUjyS#)Lzj-Z*h$AcwCnf^U+efr?0$=rb?l6GAHLJ^J$@j~dPN8D z;YS@m;Y&X6<1~ZG6LW|P)uHK&fHb)EvtI-hL_(H$qd$MI%L|+Qh-jaJi1NaJH_0xW(YX zVirhBwh)ie*KaQ(CKGc~M-;p0=n%uM0`J|>%Dyx1Wgzb5L>;?h50HhmwEK1u(AK@|wY=rguUB$J6WreG6(@F{44jxub2hgQmS_~ny_ z?IB4`nH-g~TU51}MPbW%XE{p>%DE#m@0wZPO`aZASn5PyY~*eW<0eCpt* zsKR+lWEs2>|Hez;YElkC9j_YC?Ho)5092LCrYMg?ZSdJRpg^lqlHj(%}hhl+| zgP)Z8$Pq9oSEgSl;hF3lb>NZGQ82kL-!~ZtHJtOr>Bv|co3F6J-?2;!QaX;wDEvP@ z$NpV1><?nd|=OcIafnPP}=9$RIz2=`VfAS@+lW^~(*DvD69C{DnMnWCtJ zR~FH5){nn`%D-x%t2kQMnXErt=_;*{M4~rCEmR)r+=W#htrMj#lp@p;E1gLWQpYVd z>ZH7jyHm)eeyz7Ia=4LYO$9sD&J4a(6xKlmhKvOsciZ8#)OmXKw6M;_np=GK(a0zYHa% zp8myzrhX8Gr46flIw`2k$5$^mJZ0AgvHq43_i}`zu1K3Yj16i$%y~*oW?k&*?965B zx;B@8ZY@^km}0v9l=fms7E`uS%6gf~YMRcPS&!9H$?B+Puv;?O9dI~7I8vt8;Dnk> zts|4#WX#4XA~jla%OqVqAC{HxqLo$U8^uG-Q*l}*@hhn97B(|g)G`Ry2xiomYZ_>@8TD3&ZKJGEhTzjhJ4gU~BhXQ{P+5B~YQ+{xv(4)Qr3%iNB`B$h-0=^Erk zO(WFP8Qli-y$Md2c|;t~nLJdM-YMMS7ZNqkka%X-7>1Qw45!?u_dLQu@g_I;!B@@v#{El2{#ZKfwH9KHn^e$#=Q)lJLMS<|MULl zMIRM$fIyjIhpSiN>g;z7JzSG*xBR)}+KeD-*@1$n8xkF;VF;TCvBeM?1G9!OJBY1@ zu+42~in0|gL-P=}y-|=tI-UxZV*%ax>F6A~U5r&om(@v_wQxIWTR=?*j_dvf0#Hi> z1e4KE7_)#7={^lWxCBoIF7ndu3IG7>lXg!%7x%PS+XqY40r#|6+XqY40SISU+XqY4 zlgdvk0@e_dfDk5=9Z*gJEESW079f+2P+bDn7L$M$Dw7sbP6EIflYkZu&000003hu{A delta 2874 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 Yb^$h%6;yWum_n0|R8j_iO#lD@06L$A5&!@I diff --git a/src/test/resources/zip/data-java-jdk-1.4.2.zip b/src/test/resources/zip/data-java-jdk-1.4.2.zip index b2f765e0a998d9f7000bd3cd441550dfed1f5f0d..3c92827c270907aeb1eb6c082f0609e8fe3baa04 100644 GIT binary patch delta 3035 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 delta 2966 zcmV;H3u*MBtpVh$0kF9R4!T(9PG>*?rK}170B94F4@DP~-USYSSR+Lg{+CpiRYE{f zK@I1r5EML+=tr@@Sy03h1#?)4$pSe;7B`D}_TGE%U9p^c9v+9~?7jEid+)vfGn)hi zEa7A3?aZtHE4z>UaqArbYVe1O>#)#+>pi$ZMILTc;lLslYvQJSY=FgL85NH=3&tfX zR>PP$Tbhq?+~UQ5ttxKA?OrVN;0_f(eM0hn6%XJ+A^wmT z53AfC@!(M}9`oXH@$`fT2Mhiuy?Dxlr@eT_i)RJd&2+*@?bJS3fwGl?<=Tu?+KQ&E zu4r;tccJ2ehRsgA)KuV38may{bs3_5eFdKMfMHqujT%S@#D6%e@>RD%M$fjBFEE^B|=O=)a(~R#XZwaW^U_fZa)9_q@kX6 z5=kO|)gvf1Eg3t9lRPSlnR?XHZP`stGrB;*+LhC_R?TQhNi)fDBWw)n)_}~~29?v& zHiKl<47qhNxc&AcV8VNPnUIwl)3@zoO&LQvfj3ODrDJ@s;b$;zQ%?^kEwV6r0_(&{! zXxIT^4Lf2d4IkqZ4WEkJ&v2rKF6`vN=Ni7im#nb?(e@sErQvIQ#OHnN39#bKB}0b# zKub$N!#DU=EZ;HOz{VQB$0;m~=pM0ufH$B8)WC9q{J^Y$ClJ^BH2i=cJ@`q(&-g{d zZrGheTd1!Q>T7KE8ZH+&_@7S6IjM;ZGrOroOb=AB z*7Q_d!*=Mb4p|Er`^<%>p&L7Eh=^r>p1`#S z9h@rDCcVIazJ^_}EBjO4CXCv!d`TttvuASQlytMC`wX))IwHgW$W|Eci6Ule+PF#+R_J!jxlV}N=Mes?ZlgacJ%0A6IIV}Ooj4w zkxUWf=+F@1Rj|(g>ipc)DXVOM|Cd{@Wn^>j*;~B4h3{)sPHW?tXG`%UEC%=ri&>&- z3oK(N`f9dC({iA;RkaB>+Wy52cT!LFTLa>~F>IQ8%Gxn8sBe=R-77kV`gi2FH*;2G!R(hJq!~Zj#Q$x%%OhMx3Nn z6vKxS=;Fjygg*3hS1^z>(nd*fSF{+*`IjF>5GP(MS+DOmv8Nm z+qdsHR*8h1k&r7Aa)&&NQT8AT{pI6WH8P5_5x990X;dSP`HkLxxLnS)468*P{?)?~ zr#}#mG!{l0mmfz(q)}@uaE5%&+trA}xou;Sdl_btvLDGTDHkb!m*aLd+~`*tizfi6 zK>^p*8GZn3U>4Tqx(;SzJ(kHPsAeMTaVi?H3?bZw4J1I1*dW*dNor3PfI=NtA&Eic zQO89{k#bPqc`z^pC$*l5y-2yR9yOYz+_Z2g(xg1J6NiP}nTQ_h9VV5JoeBNkq*Rc{;Fw)N(i$8)84~&tx8jCLBPjkb`nv97wNxxRB8tgoByTW%S|@ zTJ+;CdV3iCE9QPUj>yzYn7-u+G;E}+iCreq)l9B$<1wtk42Kuxz;nw=X_TO>Xp7pQ zNa{!o@?MVpjDZmMJRu#Ns$-)G9sECrVL?*IG8lz_$K{HDdS0fe1EQE`vzUW-W6g6> zARgDs)cD#HH7>QfxV947xddi2lwwPI*FLG%1G!p1K3D6_aLe8p%i8hP`BpA+tPpAL zO|~4N#LHTO!N|?<7AX()&ST?7nnm{trXab*NpF&if%ghUZl8aHPMt2!SmVbth3qUi_GT#_#>sUOb8rqP)@8i8nwqXBMoZ8y zQ483}jCuuEZ*MMI$HH8=jaZ&*lHsOE8FXog zA)6>;pUq-$YqMw8Ww+F_JL>6dD?4I)1{}c=GPE5ixgx_mNrXWurwEA8t7p$dAi2PM z?7*pib$$DmIxFRC#6is~%NK`>_b20&3>X)aN6hi2OlNhBqqe0y?-CTV$JRR!9%Td` zlBJ8vPupl!pLz-0Bhac>W$$&5{Q11R$p*`Syj+jrdK@&?ZV^$hpd+(sa9x@V;WQak zkR~-cd8%-cw}m_(k~wU$L!pLx%AF2H$rs;$Sh5$+!r2+8Ycf6O9LJpNr*!UxllsV+ z>!WjU?o`^@GUwuir6(00C$?4{m>G(WKEN{sl1A z6VR+8OYTaly^8bmYC>}jYvDSAaKofgQ)L^K)CF=}DGcbMjQOqMkX)tJ55QY}hn*aM zt-AUSXS|N@f~hlX@g&8iImM++`6WWJ_<+qQ-jX~5eYLt=C}KG;oT6*#q&`z~x>Q@2 zq`DBMgjalha~E1WGw%9><4_iL+y+O4z&Mw}b*GK681H|xQl0gf&lLLMUK= zx6s1Xx!D_~1@W6xf(<#2O3*ke#!>S^C^jm=#-rHO-#Uu663iXN=C@&s2hr=wU7pVG)B< zXFvg^tO@`CXp^H+Jr@Vm;w+;y)d2_8;w+;y)d8x&jeWrJ)RXs7D*}}eli?N8*Nh!&IK7Alj;QVf$%Q$hl97?a@^ACt0ER072rli?N-s6q8UV6qA8fP61kz&{cN=xLdle>6N-#PBYZRYIt$6+*8(XT|=B*UyD|`33)~nwga? zh3qI~BYX{eJ*nw5HKU>7<>o~2^!Cbf!#OtEbUyTyh_Hz=M#Md41Z!6Y?-ZuK+uSx=qNnd5SwV*W0z=bL%d>K>(ivUDM(x)V9!7mBaVK z)wXy+&gcaL14KLFa}&S#IS&azhgQk9eX35SK04cPx*!rpmcu{g2)>Y568YFh?1STc z^1CT!c6`8z$N{yUmwvK0OuE%Iva;fazN<0A@_CvjOemDrD;`l4cgxS%(bV3%AF$e~ zpJrJrvAhn#8$hE*dEH7AANNX?Z*$dmt_jmt+xF@3dW*!L=IBY46wAyD{Svt>$|B-@ z$Y616;g$Ow6rGgE{mk2sy!vb-m31{d(o3KuxS3ybvga~>c87e2l&zfG7B7a3_Q;wM zN>A(!!SM153X~T_yM@CL%YDyUd%3%vUL+F>4{+D3fg!o)sHeC^5VxsV-}eYH)|#wZ zna|<02RkV@@{*p1bEp6?Maah~=>^B%R+;(xtG&&Mn+(-?ax6n_#)jLQl+dhUq<+OR z)^%`oz=4bwRt@ZaZzMnWG*A_O{YiA_Ca|8>;5F>hl}&+b(s<|s^_nS8+$F%^vdD1% z;w=E^^CqH=wavSf0*$3{87Q;vUU5o?%O9IN4`d`4x!zTb{U+qnW>eTDXuSsm;yST% z#!1n&ZVR6Z^U}g%ZawCA|FZcmZQQ({I>prH5c0$wGX3XwbP%wi5X(Y?fjA3jw3~G zh8II}W@M%O^%S%*bG((yTFN2`OEA=h5beOV;*fZSNS!&CFzup{`y9NC^RXcwrNENi zU#td`28{;n4N^99M)Pv*nk`HDFZm&!^8@CEI7xwOj3EIJ10WRT_N5oM|(r2CXmXYu{1d9~kB8DgpI&PuC?fA~x z=T)QcEisJC8b9OUOcfPF=&+j9SCPFevRo&Q`>}2K<53GRU-BZM1Oz_UkCt$u~R; z7xE;t_U6)IC24X`3MQxgPDgqSd3L!(Xl@=Hp^l^bTvL9A?+2-57VSpY0-kZAWOuuo zed&eo+G3r%wgp9Zwoep_O}Tk`6Y@3cy}Xun7l(2(ALOsTe*1Z=^cv-&wUz2qbH?Me zoq&qJWB$CA>bhVSK*r=EAFw`_SS&&AWU8!^d8YCEi)V*AScMr9yb| z*{9gUV2I#h_~V)n^)R9z)XS@0$n(pr5H;5Tc|(5x^eEf}1Ja)xVK3p>O_;3OeVh#x z-*291ld)tMQtWDLwRij?x^;6uoH0FyzFcn%Ln)6bcz(cMiuHj3^r)@att5Kqc!a`& z-!%wDag}wq^U^7qm-CYbqkfIzh}tHICb0_MaWBf7K*li0K4z^(*y{c{BiFD+o?O2& z5@F$0RP3}%jEjF*PSsw7K=ml+kxqhio85T=v)mEYczJZyuC zDu%Dr7-t%xN`M}r21XohEmwq=gTIi2sDG0XG3#0OgOk6JziQfPJe9_89KgED#~I7T zJKDGhN6o*t&R($+C*^nc4oV}k>=(!0hH3?zRq_`;8~dGSP7Ad9(N{ZJ*K*tBZLvCX z>i3ZC-1L#5w$1WSHx^T(qN=oaMg&oPymNhN?OPwekbve2d-}}{RDD*vQ_z`U2aJdE zabG>vNmsg1$@rUj-l^yk>W1gcRmA1mhVd_BCw zrp(QXG0{q3JMXth%ue3bD>rgF_}-t;v+w(QM+NEKTJiK+I5m6ZmAT>_C#$&U^e+cp zK{6d=l02}l(|p-v=DDoua8k&!1@oayPs^Hf^a8Di)>Aliv&l`J5_ZZuq4FeU6trM= zt31;hK&O@L3J>+Q2U)&4+qERu;c%;K1UWi64L7%2ArGo1#dn#;1(snY?69H4nrH9! zk4~0#izcfxr2S539;2mLJGM5*=zT4_w3}q=Pz#uWmhP|!0@yC*<4)twi2jJd`ymv9 zuuHCxW3ICELEKLR6*p7AO*^*Z90qJ9Vtm%#W850JzO3X!6b6P55WAAaLYlE^kNfWL zOegm=npF1ckQN&S2VPWU1xhy%)Ptc;|Oy?a*Tpj83;yF{k0$!Bv)lj^vrEN_EYS><BI`RuWvKVCBD zcclr#Xq7*@b-0egrK;*=8;|}Ku_YB)8(~G)p3)aZ)=%nh?=0}kEBWTn^KI1ICpwwY zf-BGOd`FEW@DT166WT;qAaoIOcImw-2+@L_Lx_!yjf+jr4PwDMGrLg0&c;?Lh0S;8 z`=9p&>`B&@+I`3v=d>7v{Qo3cK%jbTARH@(ko&dl-;(*&>R50(SqLOx1wh9~a4-Ti zgo>+yZ;l9pl4=s*251FMSN~7>KzAw`O3?UE;ot<71igko)Ejs{@b?re=&Ba@##jt| znc@It>K-B{^%68s?+{NLa)HlMU7!kv|EVNcorVK%r5%Ixf=Ous&^q&9fhZ`MPJ${~ z9`40ja)Sx!R?r>$Lp`uZf{+X=$UaES@Pz`GL7NOA@O_3ebi(a0H>F*HGAM`G_%8y7 R$OL#nqf8vkJ?7u5{{hzuu@nFR delta 2421 zcmY+`c|6mP9|!PS$T4!{*vK*8ITm3i=J*z0H}SQ?a;_X9M0 zuHb8Ku%W#xsxLm+=r*V{pLyYFBFwo7#ca{cyBX z^Owa20$#BVcG5k-3z&N$mtCc9199tjthCy*O$%W=Q&giZN) zI(tZV4Mm4|yl{)JxF#=jH89~r!&F+8+=Ds2voW0;A9v6EBy1<~1VZD4dYr((8N;Z+`k2Et5gG)&^-Ij3XWQXTD5^{-u z2_0Hm$S#?(9`UE&kJAG-Hz$ztlM&^j_KV& zc!LusEKRCEkE6rE)L}yTC3&!ZSbYrD$gmx^^DV7jEeGKYB0_&^E4Pxx`y>{s116*D z#!t&kqB*Z&A4v%n><0T+D)N~5hg#No8_^fe&{10s$M!g`g@KcY*6(ST1ef{hD#uz`+e|qeS(vh~J zqCu^e**UzH-yI(6e~E& zoi#A+(}%n^=z8Yx3L81rM7DL%plXi${H7pONaCuSc9lA(FdOjny;>2razH;37uGUr z3rB%1eMN8aQ8VHt5qs4B@v1c11+^@w4=~yzFB)+l7Kn)g?2PpTM_Obtn_ouWi1!JK zs`5kN2vcYx`d9o*`f@McU(`=r)waM>{|{4+sm>>uUS4~J$sn6-_}7#XMLUM_+axYA zI}V-C_8%Od73t9RlW)Y{<9X%%DTn=Pa?TV~d$Z&<=kz5!y26}Iv#p?S8g^w~tXqHI zcs`(Xr&|Da1Y%q}L!a$_ByHk-I>pqvivg<!~z+FX3+D8x%YWdFUF*4WV(O>hO%8^vPX4r5;#BfCk%MVT?YY7wo-b=JxB z{AknICvz#i%`y08#d7lFU2lruw!m!a@uS1cg4BU`W+Gp_2MrGjJ1MV^(R8_Lm8GVl z0&)7^(ucA&=5w@SMF`#gGSygz$lc&luvfWjNilSyW-VG$jXiP7-1;V$Wixtl^Y;(F zY8ed^(?H|b?HBh)n5XDNLHO+*LGZ@s3$g8U4;TaQbXV}}+HIM_^$Zi4jb7#q!%I=x zPr^V(6XK%K(!>^$eb|jbecEs*^}_=E?jtu{;4&;2ZTdpdPCYcLJ>7CRzNi?{KAp`J zW2>+u&D_c)x{qr9)PE4DVdar=m(NA^+9nrIPE zwar;1PN>Z?e~5ymW_=y?3#M+iML(0&RV};q;o!JlRHeKHrD(c70e!>MD&sqW zg#TnLw`6zNLPd7Y-?isTi{3Dl^bt&2cpc=1?C;3zbG*7nZzdGaT7Oi;IXHj&1iFsD z`k=WzBbdBpV&=Qetu1@VZL=WeOhC?6f1)M|5<17?DK&4~(=H()srR#&KYGPg`wA8N zY?60`LVCSQ=vh{`80qiF-xl0J#Hl&&-B0HZXIgeVx5@Q~X_C(84!sOiW$UVB$c-?P zqwcVu&MFtBLIy4%-wY#;vUyV0z>koLJM7bbO6EOV4R7>fG(D>Sy+XMt~6 zs;uNUGHs1KB=ZOTX-$-9Q37aYZIlq=&+_MOM<^BKDfJkfwtFKA4hObc4=gcKBW6#M zUc?AA-b!Bin6r{)Ptd{IT$aIXpRQ(q<37!-aL-WL)d+?*W;h6pt|aIU0r;-GL&tR> zi%u_{7E5C_K1b+%HBAAxEvdxq)`kB-60F)|+5I|IB{?b1s#r%ev*peq1;h*^yMlO76xhMG9|-%VK* zPI~rj95@3U2ML}4dibRPB5(n;s<+P{6fkgv;sXlP|6e3g&Vxh^{*5@$>681+Jt+z# zJ#Yf`8UuPcvcS>jz52@6#{ulmPnffq&+2)Gv~v diff --git a/src/test/resources/zip/data-java-jdk-1.6.0.zip b/src/test/resources/zip/data-java-jdk-1.6.0.zip index 9b36cf9615f452b1d2b15070bdc9268e2e934279..af485f1c86cbd575b4b2354716a9a184997579b9 100644 GIT binary patch delta 3153 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 diff --git a/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip b/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip index 9d0e82372df66fa62d9f26973041bc6ef426988e..c3aa8b73da81da94647ad4d89acaaf6fec2cacdd 100644 GIT binary patch delta 2032 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 Olc64028$X10001;P_&N# diff --git a/src/test/resources/zip/data-java-jdk-1.7.0.zip b/src/test/resources/zip/data-java-jdk-1.7.0.zip index d78e33d74a2999a9ba9b8e48dd85a876e3f0678f..9b25f85dea4fc59896d8ca0543d9a6b86f873993 100644 GIT binary patch delta 3285 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 L0pdCTe;528H;ONn delta 3154 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 Y3?6s#gZ+mX=6X=%w*{-(EYsiT-^YXdI{*Lx diff --git a/src/test/resources/zip/data-java-jdk-1.8.0.zip b/src/test/resources/zip/data-java-jdk-1.8.0.zip index 53c666dd52b2f5483251ee2c48f39cb05ccba173..3e0c09d37c2e31db4d155245af4576667472c2c8 100644 GIT binary patch delta 3311 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 R96$?`qEj>m7fb*E002=Z`j7ws delta 3015 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 J+DiZc008zux!3>z diff --git a/src/test/resources/zip/data-java-jdk-9.0.1.zip b/src/test/resources/zip/data-java-jdk-9.0.1.zip index d4c995eee2f92787495419dd64d50faded25c9ec..b0086483c9d0c549d3e95ea863bc19cc39ae3fd3 100644 GIT binary patch delta 3097 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 delta 3019 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 N#Zx~9$x8qL004@u!ax83 From e5faeac2b727bf28e65ed3c372030a7c317c5a38 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 11 Aug 2019 16:01:44 +0200 Subject: [PATCH 054/211] Update object type maker --- .../model/classfile/attribute/Annotation.java | 12 +- .../attribute/ElementValueEnumConstValue.java | 12 +- .../expression/ArrayExpression.java | 6 +- .../expression/IntegerConstantExpression.java | 18 +- .../v1/model/javasyntax/type/ObjectType.java | 84 ++++++--- .../model/javasyntax/type/PrimitiveType.java | 79 +++++---- .../model/localvariable/Frame.java | 105 +++++------ .../localvariable/ObjectLocalVariable.java | 19 +- .../localvariable/PrimitiveLocalVariable.java | 37 ++-- .../util/AnnotationConverter.java | 23 ++- .../util/ByteCodeParser.java | 161 +++++------------ .../util/ControlFlowGraphReducer.java | 4 +- .../util/LocalVariableMaker.java | 18 +- .../util/ObjectTypeMaker.java | 165 +++++++++++------- .../util/PrimitiveTypeUtil.java | 57 +++--- .../util/SignatureParser.java | 14 +- .../util/StatementMaker.java | 14 +- .../GenerateParameterSuffixNameVisitor.java | 3 +- .../visitor/InitInnerClassVisitor.java | 8 +- .../UpdateIntegerConstantTypeVisitor.java | 6 +- .../classfile/ClassFileDeserializer.java | 18 +- .../visitor/ExpressionVisitor.java | 5 +- .../visitor/SearchImportsVisitor.java | 28 +-- .../visitor/TypeVisitor.java | 3 +- .../jd/core/v1/AnnotationConverterTest.java | 4 +- .../jd/core/v1/ClassFileDeserializerTest.java | 4 +- .../org/jd/core/v1/ObjectTypeMakerTest.java | 44 ++--- .../type/visitor/PrintTypeVisitor.java | 2 +- 28 files changed, 488 insertions(+), 465 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java index 31475e98..ff9c90a5 100644 --- a/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/Annotation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,16 +8,16 @@ package org.jd.core.v1.model.classfile.attribute; public class Annotation { - protected String typeName; + protected String descriptor; protected ElementValuePair[] elementValuePairs; - public Annotation(String typeName, ElementValuePair[] elementValuePairs) { - this.typeName = typeName; + public Annotation(String descriptor, ElementValuePair[] elementValuePairs) { + this.descriptor = descriptor; this.elementValuePairs = elementValuePairs; } - public String getTypeName() { - return typeName; + public String getDescriptor() { + return descriptor; } public ElementValuePair[] getElementValuePairs() { diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java index 77c2a02d..1e926e09 100644 --- a/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/ElementValueEnumConstValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,16 +8,16 @@ package org.jd.core.v1.model.classfile.attribute; public class ElementValueEnumConstValue implements ElementValue { - protected String typeName; + protected String descriptor; protected String constName; - public ElementValueEnumConstValue(String typeName, String constName) { - this.typeName = typeName; + public ElementValueEnumConstValue(String descriptor, String constName) { + this.descriptor = descriptor; this.constName = constName; } - public String getTypeName() { - return typeName; + public String getDescriptor() { + return descriptor; } public String getConstName() { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java index ed1ff288..aaa0ac7f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -9,6 +9,8 @@ import org.jd.core.v1.model.javasyntax.type.Type; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; + public class ArrayExpression extends AbstractLineNumberTypeExpression { protected Expression expression; protected Expression index; @@ -50,7 +52,7 @@ protected static Type createItemType(Expression expression) { Type type = expression.getType(); int dimension = type.getDimension(); - assert dimension > 0 : "createItemType : negative dimension"; + assert (type == TYPE_UNDEFINED_OBJECT) || (dimension > 0) : "ArrayExpression.createItemType(exp) : zero or negative dimension"; return type.createType((dimension > 0) ? dimension-1 : 0); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java index 74aec084..7175cba0 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -35,24 +35,14 @@ public int getValue() { @Override public void setType(Type type) { - assert type.isPrimitive() && checkType(type) : "setType : incompatible types"; + assert checkType(type) : "IntegerConstantExpression.setType(type) : incompatible types"; super.setType(type); } protected boolean checkType(Type type) { if (type.isPrimitive()) { - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(((PrimitiveType)type).getFlags())) { - case FLAG_BYTE: - return (Byte.MIN_VALUE <= value) && (value <= Byte.MAX_VALUE); - case FLAG_CHAR: - return (Character.MIN_VALUE <= (char)value) && ((char)value <= Character.MAX_VALUE); - case FLAG_SHORT: - return (Short.MIN_VALUE <= value) && (value <= Short.MAX_VALUE); - case FLAG_BOOLEAN: - return (0 <= value) && (value <= 1); - default: - return (Integer.MIN_VALUE <= value) && (value <= Integer.MAX_VALUE); - } + PrimitiveType valueType = PrimitiveTypeUtil.getPrimitiveTypeFromValue(value); + return (((PrimitiveType)type).getFlags() & valueType.getFlags()) != 0; } return false; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index 4c1bc166..01f51687 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -8,19 +8,35 @@ package org.jd.core.v1.model.javasyntax.type; public class ObjectType implements Type { - public static final ObjectType TYPE_BOOLEAN = new ObjectType("java/lang/Boolean", "java.lang.Boolean", "Boolean"); - public static final ObjectType TYPE_BYTE = new ObjectType("java/lang/Byte", "java.lang.Byte", "Byte"); - public static final ObjectType TYPE_CHARACTER = new ObjectType("java/lang/Character", "java.lang.Character", "Character"); - public static final ObjectType TYPE_CLASS = new ObjectType("java/lang/Class", "java.lang.Class", "Class"); - public static final ObjectType TYPE_DOUBLE = new ObjectType("java/lang/Double", "java.lang.Double", "Double"); - public static final ObjectType TYPE_FLOAT = new ObjectType("java/lang/Float", "java.lang.Float", "Float"); - public static final ObjectType TYPE_INTEGER = new ObjectType("java/lang/Integer", "java.lang.Integer", "Integer"); - public static final ObjectType TYPE_LONG = new ObjectType("java/lang/Long", "java.lang.Long", "Long"); - public static final ObjectType TYPE_MATH = new ObjectType("java/lang/Math", "java.lang.Math", "Math"); - public static final ObjectType TYPE_OBJECT = new ObjectType("java/lang/Object", "java.lang.Object", "Object"); - public static final ObjectType TYPE_SHORT = new ObjectType("java/lang/Short", "java.lang.Short", "Short"); - public static final ObjectType TYPE_STRING = new ObjectType("java/lang/String", "java.lang.String", "String"); - public static final ObjectType TYPE_THROWABLE = new ObjectType("java/lang/Throwable", "java.lang.Throwable", "Throwable"); + public static final ObjectType TYPE_BOOLEAN = new ObjectType("java/lang/Boolean", "java.lang.Boolean", "Boolean"); + public static final ObjectType TYPE_BYTE = new ObjectType("java/lang/Byte", "java.lang.Byte", "Byte"); + public static final ObjectType TYPE_CHARACTER = new ObjectType("java/lang/Character", "java.lang.Character", "Character"); + public static final ObjectType TYPE_CLASS = new ObjectType("java/lang/Class", "java.lang.Class", "Class"); + public static final ObjectType TYPE_DOUBLE = new ObjectType("java/lang/Double", "java.lang.Double", "Double"); + public static final ObjectType TYPE_EXCEPTION = new ObjectType("java/lang/Exception", "java.lang.Exception", "Exception"); + public static final ObjectType TYPE_FLOAT = new ObjectType("java/lang/Float", "java.lang.Float", "Float"); + public static final ObjectType TYPE_INTEGER = new ObjectType("java/lang/Integer", "java.lang.Integer", "Integer"); + public static final ObjectType TYPE_LONG = new ObjectType("java/lang/Long", "java.lang.Long", "Long"); + public static final ObjectType TYPE_MATH = new ObjectType("java/lang/Math", "java.lang.Math", "Math"); + public static final ObjectType TYPE_OBJECT = new ObjectType("java/lang/Object", "java.lang.Object", "Object"); + public static final ObjectType TYPE_RUNTIME_EXCEPTION = new ObjectType("java/lang/RuntimeException", "java.lang.RuntimeException", "RuntimeException"); + public static final ObjectType TYPE_SHORT = new ObjectType("java/lang/Short", "java.lang.Short", "Short"); + public static final ObjectType TYPE_STRING = new ObjectType("java/lang/String", "java.lang.String", "String"); + public static final ObjectType TYPE_STRING_BUFFER = new ObjectType("java/lang/StringBuffer", "java.lang.StringBuffer", "StringBuffer"); + public static final ObjectType TYPE_STRING_BUILDER = new ObjectType("java/lang/StringBuilder", "java.lang.StringBuilder", "StringBuilder"); + public static final ObjectType TYPE_SYSTEM = new ObjectType("java/lang/System", "java.lang.System", "System"); + public static final ObjectType TYPE_THREAD = new ObjectType("java/lang/Thread", "java.lang.Thread", "Thread"); + public static final ObjectType TYPE_THROWABLE = new ObjectType("java/lang/Throwable", "java.lang.Throwable", "Throwable"); + + public static final ObjectType TYPE_PRIMITIVE_BOOLEAN = new ObjectType("Z"); + public static final ObjectType TYPE_PRIMITIVE_BYTE = new ObjectType("B"); + public static final ObjectType TYPE_PRIMITIVE_CHAR = new ObjectType("C"); + public static final ObjectType TYPE_PRIMITIVE_DOUBLE = new ObjectType("D"); + public static final ObjectType TYPE_PRIMITIVE_FLOAT = new ObjectType("F"); + public static final ObjectType TYPE_PRIMITIVE_INT = new ObjectType("I"); + public static final ObjectType TYPE_PRIMITIVE_LONG = new ObjectType("J"); + public static final ObjectType TYPE_PRIMITIVE_SHORT = new ObjectType("S"); + public static final ObjectType TYPE_PRIMITIVE_VOID = new ObjectType("V"); public static final ObjectType TYPE_UNDEFINED_OBJECT = new ObjectType("java/lang/Object", "java.lang.Object", "Object") { @Override public String toString() { return "UndefinedObjectType"; } @@ -52,22 +68,32 @@ public ObjectType(String internalName, String qualifiedName, String name, BaseTy this.name = name; this.typeArguments = typeArguments; this.dimension = dimension; + this.descriptor = createDescriptor("L" + internalName + ';', dimension); assert (internalName != null) && !internalName.endsWith(";"); + } + + public ObjectType(String primitiveDescriptor) { + this(primitiveDescriptor, 0); + } + + public ObjectType(String primitiveDescriptor, int dimension) { + this.internalName = primitiveDescriptor; + this.qualifiedName = this.name = PrimitiveType.getPrimitiveType(primitiveDescriptor.charAt(0)).getName(); + this.dimension = dimension; + this.descriptor = createDescriptor(primitiveDescriptor, dimension); + } + protected static String createDescriptor(String descriptor, int dimension) { switch (dimension) { case 0: - this.descriptor = "L" + internalName + ';'; - break; + return descriptor; case 1: - this.descriptor = "[L" + internalName + ';'; - break; + return "[" + descriptor; case 2: - this.descriptor = "[[L" + internalName + ';'; - break; + return "[[" + descriptor; default: - this.descriptor = new String(new char[dimension]).replaceAll("\0", "[") + 'L' + internalName + ';'; - break; + return new String(new char[dimension]).replaceAll("\0", "[") + descriptor; } } @@ -109,11 +135,21 @@ public int getDimension() { @Override public Type createType(int dimension) { - assert dimension >= 0; - if (this.dimension == dimension) + assert dimension >= 0 : "ObjectType.createType(dim) : create type with zero or negative dimension"; + + if (this.dimension == dimension) { return this; - else + } else if (descriptor.charAt(descriptor.length()-1) != ';') { + // Array of primitive types + if (dimension == 0) { + return PrimitiveType.getPrimitiveType(descriptor.charAt(this.dimension)); + } else { + return new ObjectType(internalName, dimension); + } + } else { + // Object type or array of object types return new ObjectType(internalName, qualifiedName, name, typeArguments, dimension); + } } public ObjectType createType(BaseTypeArgument typeArguments) { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java index f25ba239..edaa6829 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java @@ -38,37 +38,38 @@ public class PrimitiveType implements Type { public static final PrimitiveType MAYBE_INT_TYPE = new PrimitiveType("maybe_int", FLAG_INT, FLAG_INT, FLAG_INT); // Otherwise public static final PrimitiveType MAYBE_NEGATIVE_BOOLEAN_TYPE = new PrimitiveType("maybe_negative_boolean", FLAG_BOOLEAN|FLAG_BYTE|FLAG_SHORT|FLAG_INT, FLAG_BOOLEAN|FLAG_BYTE|FLAG_SHORT|FLAG_INT, FLAG_BOOLEAN|FLAG_BYTE|FLAG_SHORT|FLAG_INT); // Boolean or negative - protected String name; - protected int dimension; - protected int flags; - protected int leftFlags; - protected int rightFlags; - protected String descriptor; - - protected PrimitiveType(String name, int flags, int leftFlags, int rightFlags) { - this(name, flags, leftFlags, rightFlags, 0); + protected static final PrimitiveType[] descriptorToType = new PrimitiveType['Z' - 'B' + 1]; + + static { + descriptorToType['B' - 'B'] = TYPE_BYTE; + descriptorToType['C' - 'B'] = TYPE_CHAR; + descriptorToType['D' - 'B'] = TYPE_DOUBLE; + descriptorToType['F' - 'B'] = TYPE_FLOAT; + descriptorToType['I' - 'B'] = TYPE_INT; + descriptorToType['J' - 'B'] = TYPE_LONG; + descriptorToType['S' - 'B'] = TYPE_SHORT; + descriptorToType['V' - 'B'] = TYPE_VOID; + descriptorToType['Z' - 'B'] = TYPE_BOOLEAN; } - protected PrimitiveType(PrimitiveType primitiveType, int dimension) { - this(primitiveType.name, primitiveType.flags, primitiveType.leftFlags, primitiveType.rightFlags, dimension); + protected final String name; + protected final int flags; + protected final int leftFlags; + protected final int rightFlags; + protected final String descriptor; + + protected PrimitiveType(PrimitiveType primitiveType) { + this(primitiveType.name, primitiveType.flags, primitiveType.leftFlags, primitiveType.rightFlags); } - protected PrimitiveType(String name, int flags, int leftFlags, int rightFlags, int dimension) { + protected PrimitiveType(String name, int flags, int leftFlags, int rightFlags) { this.name = name; - this.dimension = dimension; this.flags = flags; this.leftFlags = leftFlags; this.rightFlags = rightFlags; StringBuilder sb = new StringBuilder(); - switch (dimension) { - case 0: break; - case 1: sb.append('['); break; - case 2: sb.append("[["); break; - default: for (int i=0; i= 0; - if (this.dimension == dimension) + public Type createType(int dimension) { + assert dimension >= 0 : "PrimitiveType.createType(dim) : create type with zero or negative dimension"; + if (dimension == 0) { return this; - else - return new PrimitiveType(this, dimension); + } else { + return new ObjectType(descriptor, dimension); + } } @Override @@ -132,7 +138,6 @@ public boolean equals(Object o) { PrimitiveType that = (PrimitiveType) o; - if (dimension != that.dimension) return false; if (flags != that.flags) return false; return true; @@ -140,7 +145,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return 31 * dimension + flags; + return flags; } @Override @@ -155,9 +160,19 @@ public boolean isPrimitive() { @Override public String toString() { - if (dimension == 0) - return "PrimitiveType{primitive=" + name + "}"; - else - return "PrimitiveType{primitive=" + name + ", dimension=" + dimension + "}"; + return "PrimitiveType{primitive=" + name + "}"; + } + + public int getJavaPrimitiveFlags() { + if ((flags & FLAG_BOOLEAN) != 0) + return FLAG_BOOLEAN; + else if ((flags & FLAG_BYTE) != 0) + return FLAG_BYTE; + else if ((flags & FLAG_CHAR) != 0) + return FLAG_CHAR; + else if ((flags & FLAG_SHORT) != 0) + return FLAG_SHORT; + + return flags; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 71cbff9f..8fe3ff50 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -16,7 +16,6 @@ import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchUndeclaredLocalVariableVisitor; import org.jd.core.v1.util.DefaultList; @@ -40,7 +39,7 @@ public Frame(Frame parent, Statements statements) { } public void addLocalVariable(AbstractLocalVariable lv) { - assert lv.getNext() == null; + assert lv.getNext() == null : "Frame.addLocalVariable(lv) : add local variable failed"; int index = lv.getIndex(); @@ -109,19 +108,20 @@ public void mergeLocalVariable(AbstractLocalVariable lv) { Type type = lv.getType(); Type alvToMergeType = alvToMerge.getType(); - assert (type.isPrimitive() == alvToMergeType.isPrimitive()) && (type.isObject() == alvToMergeType.isObject()) && (type.isGeneric() == alvToMergeType.isGeneric()); + assert (type.isPrimitive() == alvToMergeType.isPrimitive()) && (type.isObject() == alvToMergeType.isObject()) && (type.isGeneric() == alvToMergeType.isGeneric()) : "Frame.mergeLocalVariable(lv) : merge local variable failed"; if (type.isPrimitive()) { if (alvToMerge.isAssignableFrom(lv)) { - ((PrimitiveLocalVariable)lv).setPrimitiveType((PrimitiveType)type); - } else { - ((PrimitiveLocalVariable)lv).setPrimitiveType(PrimitiveType.TYPE_INT); + ((PrimitiveLocalVariable)lv).setType((PrimitiveType)alvToMergeType); + } else if (!lv.isAssignableFrom(alvToMerge)) { + ((PrimitiveLocalVariable)lv).setType(PrimitiveType.TYPE_INT); } } else if (type.isObject()) { if (alvToMerge.isAssignableFrom(lv)) { - ((ObjectLocalVariable)lv).setObjectType((ObjectType)type); - } else { - ((ObjectLocalVariable)lv).setObjectType(ObjectType.TYPE_OBJECT); + ((ObjectLocalVariable)lv).setType(alvToMergeType); + } else if (!lv.isAssignableFrom(alvToMerge)) { + int dimension = Math.max(lv.getDimension(), alvToMerge.getDimension()); + ((ObjectLocalVariable)lv).setType(ObjectType.TYPE_OBJECT.createType(dimension)); } } } @@ -148,6 +148,7 @@ public void removeLocalVariable(AbstractLocalVariable lv) { } } else { localVariableArray[index] = alvToRemove.getNext(); + alvToRemove.setNext(null); } } @@ -724,45 +725,23 @@ public String getName() { public void visit(PrimitiveType type) { sb.setLength(0); - switch (type.getDimension()) { - case 0: - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(type.getFlags())) { - case FLAG_BYTE : sb.append("b"); break; - case FLAG_CHAR : sb.append("c"); break; - case FLAG_DOUBLE : sb.append("d"); break; - case FLAG_FLOAT : sb.append("f"); break; - case FLAG_INT : - for (String in : INTEGER_NAMES) { - if (!blackListNames.contains(in)) { - blackListNames.add(name = in); - return; - } - } - sb.append("i"); - break; - case FLAG_LONG : sb.append("l"); break; - case FLAG_SHORT : sb.append("s"); break; - case FLAG_BOOLEAN : sb.append("bool"); break; - } - break; - default: -// case 1: - sb.append("arrayOf"); - - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(type.getFlags())) { - case FLAG_BYTE : sb.append("Byte"); break; - case FLAG_CHAR : sb.append("Char"); break; - case FLAG_DOUBLE : sb.append("Double"); break; - case FLAG_FLOAT : sb.append("Float"); break; - case FLAG_INT : sb.append("Int"); break; - case FLAG_LONG : sb.append("Long"); break; - case FLAG_SHORT : sb.append("Short"); break; - case FLAG_BOOLEAN : sb.append("Boolean"); break; + switch (type.getJavaPrimitiveFlags()) { + case FLAG_BYTE : sb.append("b"); break; + case FLAG_CHAR : sb.append("c"); break; + case FLAG_DOUBLE : sb.append("d"); break; + case FLAG_FLOAT : sb.append("f"); break; + case FLAG_INT : + for (String in : INTEGER_NAMES) { + if (!blackListNames.contains(in)) { + blackListNames.add(name = in); + return; + } } + sb.append("i"); break; -// default: -// sb.append("arrayOfArray"); -// break; + case FLAG_LONG : sb.append("l"); break; + case FLAG_SHORT : sb.append("s"); break; + case FLAG_BOOLEAN : sb.append("bool"); break; } generate(type); @@ -800,7 +779,8 @@ protected void visit(Type type, String str) { break; default: // case 1: - sb.append("arrayOf").append(str); + sb.append("arrayOf"); + capitalize(str); break; // default: // sb.append("arrayOfArray"); @@ -810,14 +790,39 @@ protected void visit(Type type, String str) { generate(type); } + protected void capitalize(String str) { + if (str != null) { + int length = str.length(); + + if (length > 0) { + char firstChar = str.charAt(0); + + if (Character.isUpperCase(firstChar)) { + sb.append(str); + } else { + sb.append(Character.toUpperCase(firstChar)); + if (length > 1) { + sb.append(str.substring(1)); + } + } + } + } + } + protected void uncapitalize(String str) { if (str != null) { int length = str.length(); if (length > 0) { - sb.append(Character.toLowerCase(str.charAt(0))); - if (length > 1) { - sb.append(str.substring(1)); + char firstChar = str.charAt(0); + + if (Character.isLowerCase(firstChar)) { + sb.append(str); + } else { + sb.append(Character.toLowerCase(firstChar)); + if (length > 1) { + sb.append(str.substring(1)); + } } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 6dc2afcd..b1066223 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -11,8 +11,7 @@ import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; -import java.util.HashSet; - +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; public class ObjectLocalVariable extends AbstractLocalVariable { @@ -41,7 +40,7 @@ public Type getType() { return type; } - public void setObjectType(ObjectType type) { + public void setType(Type type) { if (!this.type.equals(type)) { this.type = type; fireChangeEvent(); @@ -80,10 +79,12 @@ public String toString() { @Override public boolean isAssignableFrom(Type type) { - if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || this.type.equals(type)) { - return true; - } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0) && this.type.isObject() && type.isObject()) { - return objectTypeMaker.isAssignable((ObjectType)this.type, (ObjectType)type); + if (!type.isPrimitive()) { + if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_OBJECT) || this.type.equals(type)) { + return true; + } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0) && this.type.isObject() && type.isObject()) { + return objectTypeMaker.isAssignable((ObjectType) this.type, (ObjectType) type); + } } return false; @@ -95,7 +96,7 @@ public void typeOnRight(Type type) { this.type = type; fireChangeEvent(); } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { - assert !this.type.isPrimitive() && !type.isPrimitive(); + assert !this.type.isPrimitive() && !type.isPrimitive() : "ObjectLocalVariable.typeOnRight(type) : unexpected type"; if (this.type.isObject() && type.isObject()) { ObjectType thisObjectType = (ObjectType)this.type; @@ -126,7 +127,7 @@ public void typeOnLeft(Type type) { this.type = type; fireChangeEvent(); } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { - assert !this.type.isPrimitive() && !type.isPrimitive(); + assert !this.type.isPrimitive() && !type.isPrimitive() : "unexpected type in ObjectLocalVariable.typeOnLeft(type)"; if (this.type.isObject() && type.isObject()) { ObjectType thisObjectType = (ObjectType)this.type; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java index c2c2fde7..3695071e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java @@ -9,8 +9,7 @@ import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; - -import java.util.HashSet; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; @@ -19,13 +18,11 @@ public class PrimitiveLocalVariable extends AbstractLocalVariable { public PrimitiveLocalVariable(int index, int offset, PrimitiveType type, String name) { super(index, offset, name); - assert type.getDimension() == 0; this.flags = type.getFlags(); } public PrimitiveLocalVariable(int index, int offset, PrimitiveLocalVariable primitiveLocalVariable) { super(index, offset, null); - assert primitiveLocalVariable.getDimension() == 0; int valueFlags = primitiveLocalVariable.flags; if ((valueFlags & FLAG_INT) != 0) { @@ -87,8 +84,7 @@ public int getDimension() { return 0; } - public void setPrimitiveType(PrimitiveType type) { - assert type.getDimension() == 0; + public void setType(PrimitiveType type) { this.flags = type.getFlags(); } @@ -168,7 +164,14 @@ public void typeOnLeft(Type type) { @Override public boolean isAssignableFrom(AbstractLocalVariable variable) { if (variable.getClass() == PrimitiveLocalVariable.class) { - return (flags & ((PrimitiveLocalVariable)variable).flags) != 0; + int variableFlags = ((PrimitiveLocalVariable)variable).flags; + PrimitiveType type = PrimitiveTypeUtil.getPrimitiveTypeFromFlags(variableFlags); + + if (type != null) { + variableFlags = type.getRightFlags(); + } + + return (flags & variableFlags) != 0; } return false; @@ -181,9 +184,15 @@ public void variableOnRight(AbstractLocalVariable variable) { addVariableOnRight(variable); int old = flags; + int variableFlags = ((PrimitiveLocalVariable)variable).flags; + PrimitiveType type = PrimitiveTypeUtil.getPrimitiveTypeFromFlags(variableFlags); - flags &= ((PrimitiveLocalVariable)variable).flags; - assert flags != 0; + if (type != null) { + variableFlags = type.getRightFlags(); + } + + flags &= variableFlags; + assert flags != 0 : "PrimitiveLocalVariable.variableOnRight(var) : flags = 0 after type reduction"; if (old != flags) { fireChangeEvent(); @@ -197,9 +206,15 @@ public void variableOnLeft(AbstractLocalVariable variable) { addVariableOnLeft(variable); int old = flags; + int variableFlags = ((PrimitiveLocalVariable)variable).flags; + PrimitiveType type = PrimitiveTypeUtil.getPrimitiveTypeFromFlags(variableFlags); + + if (type != null) { + variableFlags = type.getLeftFlags(); + } - flags &= ((PrimitiveLocalVariable)variable).flags; - assert flags != 0; + flags &= variableFlags; + assert flags != 0 : "PrimitiveLocalVariable.variableOnLeft(var) : flags = 0 after type reduction"; if (old != flags) { fireChangeEvent(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java index cd70fdf4..258c9fae 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -69,11 +69,11 @@ protected BaseAnnotationReference convert(Annotations annotations) { @SuppressWarnings("unchecked") protected AnnotationReference convert(Annotation annotation) { - String typeName = annotation.getTypeName(); + String descriptor = annotation.getDescriptor(); - assert (typeName != null) && (typeName.length() > 2) && (typeName.charAt(0) == 'L') && (typeName.charAt(typeName.length()-1) == ';'); + assert (descriptor != null) && (descriptor.length() > 2) && (descriptor.charAt(0) == 'L') && (descriptor.charAt(descriptor.length()-1) == ';'); - ObjectType ot = factory.make(typeName); + ObjectType ot = factory.makeFromDescriptor(descriptor); ElementValuePair[] elementValuePairs = annotation.getElementValuePairs(); if (elementValuePairs == null) { @@ -145,10 +145,7 @@ public void visit(ElementValuePrimitiveType elementValuePrimitiveType) { @Override public void visit(ElementValueClassInfo elementValueClassInfo) { String classInfo = elementValueClassInfo.getClassInfo(); - - assert (classInfo != null) && (classInfo.length() > 2) && (classInfo.charAt(0) == 'L') && (classInfo.charAt(classInfo.length()-1) == ';'); - - ObjectType ot = factory.make(classInfo); + ObjectType ot = factory.makeFromDescriptor(classInfo); elementValue = new ExpressionElementValue(new TypeReferenceDotClassExpression(ot)); } @@ -161,14 +158,14 @@ public void visit(ElementValueAnnotationValue elementValueAnnotationValue) { @Override public void visit(ElementValueEnumConstValue elementValueEnumConstValue) { - String typeName = elementValueEnumConstValue.getTypeName(); + String descriptor = elementValueEnumConstValue.getDescriptor(); - assert (typeName != null) && (typeName.length() > 2) && (typeName.charAt(0) == 'L') && (typeName.charAt(typeName.length()-1) == ';'); + assert (descriptor != null) && (descriptor.length() > 2) && (descriptor.charAt(0) == 'L') && (descriptor.charAt(descriptor.length()-1) == ';') : "AnnotationConverter.visit(elementValueEnumConstValue)"; - String descriptor = typeName.substring(1, typeName.length()-1); - ObjectType ot = factory.make(descriptor); + ObjectType ot = factory.makeFromDescriptor(descriptor); String constName = elementValueEnumConstValue.getConstName(); - elementValue = new ExpressionElementValue(new FieldReferenceExpression(ot, new ObjectTypeReferenceExpression(ot), descriptor, constName, descriptor)); + String internalTypeName = descriptor.substring(1, descriptor.length()-1); + elementValue = new ExpressionElementValue(new FieldReferenceExpression(ot, new ObjectTypeReferenceExpression(ot), internalTypeName, constName, descriptor)); } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 611176dc..cb9724c7 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -244,7 +244,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau indexRef = stack.pop(); arrayRef = stack.pop(); t = arrayRef.getType(); - statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, t.createType(t.getDimension()-1), new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); + statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, t.createType(t.getDimension()>0 ? t.getDimension()-1 : 0), new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); break; case 84: // BASTORE valueRef = stack.pop(); @@ -722,27 +722,15 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 182: case 183: case 184: case 185: // INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ot = objectTypeMaker.make(typeName); + ot = (typeName.charAt(0) == '[') ? + objectTypeMaker.makeFromDescriptor(typeName) : + objectTypeMaker.makeFromInternalTypeName(typeName); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); BaseExpression parameters = getParameters(statements, stack, descriptor); Type returnedType = signatureParser.parseReturnedType(descriptor); -// if (!statements.isEmpty() && (opcode == 184)) { // INVOKESTATIC -// Statement last = statements.getLast(); -// -// if (last.getClass() == ExpressionStatement.class) { -// Expression expression = ((ExpressionStatement)last).getExpression(); -// -// if ((expression.getLineNumber() == lineNumber) && (expression.getType().equals(ot))) { -// statements.removeLast(); -// stack.push(expression); -// opcode = 0; -// } -// } -// } - if (opcode == 184) { // INVOKESTATIC expression1 = new MethodInvocationExpression(lineNumber, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameters); if (TYPE_VOID.equals(returnedType)) { @@ -752,6 +740,9 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } } else { expression1 = stack.pop(); + if (expression1.getClass() == ClassFileLocalVariableReferenceExpression.class) { + ((ClassFileLocalVariableReferenceExpression)expression1).getLocalVariable().typeOnLeft(ot); + } if (opcode == 185) { // INVOKEINTERFACE offset += 2; // Skip 'count' and one byte } @@ -791,12 +782,17 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau stack.push(newNewExpression(lineNumber, typeName)); break; case 188: // NEWARRAY - type1 = parsePrimitiveTypeForNewArray( (code[++offset] & 255) ); + type1 = PrimitiveTypeUtil.getPrimitiveTypeFromTag( (code[++offset] & 255) ).createType(1); stack.push(new NewArray(lineNumber, type1, stack.pop())); break; case 189: // ANEWARRAY typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - type1 = parseTypeNameForNewArray(typeName); + if (typeName.charAt(0) == '[') { + type1 = objectTypeMaker.makeFromDescriptor(typeName); + type1 = type1.createType(type1.getDimension()+1); + } else { + type1 = objectTypeMaker.makeFromInternalTypeName(typeName).createType(1); + } stack.push(new NewArray(lineNumber, type1, stack.pop())); break; case 190: // ARRAYLENGTH @@ -807,10 +803,9 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 192: // CHECKCAST typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - t = objectTypeMaker.make(typeName); - if (t == null) { - t = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); - } + t = (typeName.charAt(0) == '[') ? + objectTypeMaker.makeFromDescriptor(typeName) : + objectTypeMaker.makeFromInternalTypeName(typeName); expression1 = stack.pop(); if (expression1.getClass() == CastExpression.class) { // Skip double cast @@ -824,7 +819,9 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 193: // INSTANCEOF typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - t = objectTypeMaker.make(typeName); + t = (typeName.charAt(0) == '[') ? + objectTypeMaker.makeFromDescriptor(typeName) : + objectTypeMaker.makeFromInternalTypeName(typeName); if (t == null) { t = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); } @@ -879,7 +876,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 197: // MULTIANEWARRAY typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - type1 = parseTypeNameForMultiNewArray(typeName); + type1 = objectTypeMaker.makeFromDescriptor(typeName); i = code[++offset] & 255; Expressions dimensions = new Expressions(i); @@ -1010,8 +1007,9 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in case Constant.CONSTANT_Class: int typeNameIndex = ((ConstantClass) constant).getNameIndex(); String typeName = ((ConstantUtf8)constants.getConstant(typeNameIndex)).getValue(); - Type type = objectTypeMaker.make(typeName); - + Type type = (typeName.charAt(0) == '[') ? + objectTypeMaker.makeFromDescriptor(typeName) : + objectTypeMaker.makeFromInternalTypeName(typeName); if (type == null) { type = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); } @@ -1331,7 +1329,7 @@ private void parseInvokeDynamic(Statements statements, DefaultStack")) { stack.push(new ConstructorReferenceExpression(lineNumber, indyType, ot, descriptor1)); @@ -1577,7 +1575,7 @@ private static void parseIF(DefaultStack stack, int lineNumber, Basi } else if (expression.getType().isPrimitive()) { PrimitiveType pt = (PrimitiveType)expression.getType(); - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(pt.getFlags())) { + switch (pt.getJavaPrimitiveFlags()) { case FLAG_BOOLEAN: if (basicBlock.mustInverseCondition() ^ "==".equals(operator1)) stack.push(expression); @@ -1677,7 +1675,7 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); - ObjectType ot = objectTypeMaker.make(typeName); + ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); stack.push(new FieldReferenceExpression(lineNumber, type, objectRef, typeName, name, descriptor)); } @@ -1685,7 +1683,7 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan private void parsePutStatic(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ObjectType ot = objectTypeMaker.make(typeName); + ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); @@ -1699,7 +1697,7 @@ private void parsePutStatic(Statements statements, DefaultStack stac private void parseGetField(DefaultStack stack, ConstantPool constants, int lineNumber, int index) { ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ObjectType ot = objectTypeMaker.make(typeName); + ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); @@ -1711,7 +1709,7 @@ private void parseGetField(DefaultStack stack, ConstantPool constant private void parsePutField(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ObjectType ot = objectTypeMaker.make(typeName); + ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); @@ -1737,19 +1735,23 @@ private static Expression getLastRightExpression(BinaryOperatorExpression boe) { } private Expression newNewExpression(int lineNumber, String internalName) { - ObjectType objectType = objectTypeMaker.make(internalName); + ObjectType objectType = objectTypeMaker.makeFromInternalTypeName(internalName); if ((objectType.getQualifiedName() == null) && (objectType.getName() == null)) { - ClassFileClassDeclaration declaration = (ClassFileClassDeclaration)bodyDeclaration.getInnerTypeDeclaration(internalName); + ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); - if (declaration == null) { + if (memberDeclaration == null) { return new NewExpression(lineNumber, ObjectType.TYPE_OBJECT); - } else if (declaration.getInterfaces() != null) { - return new NewExpression(lineNumber, (ObjectType)declaration.getInterfaces(), declaration.getBodyDeclaration()); - } else if (declaration.getSuperType() != null) { - return new NewExpression(lineNumber, (ObjectType)declaration.getSuperType(), declaration.getBodyDeclaration()); - } else { - return new NewExpression(lineNumber, ObjectType.TYPE_OBJECT, declaration.getBodyDeclaration()); + } else if (memberDeclaration.getClass() == ClassFileClassDeclaration.class) { + ClassFileClassDeclaration declaration = (ClassFileClassDeclaration) memberDeclaration; + + if (declaration.getInterfaces() != null) { + return new NewExpression(lineNumber, (ObjectType) declaration.getInterfaces(), declaration.getBodyDeclaration()); + } else if (declaration.getSuperType() != null) { + return new NewExpression(lineNumber, (ObjectType) declaration.getSuperType(), declaration.getBodyDeclaration()); + } else { + return new NewExpression(lineNumber, ObjectType.TYPE_OBJECT, declaration.getBodyDeclaration()); + } } } @@ -1903,83 +1905,14 @@ private static void reduceIntegerLocalVariableType(Expression expression) { } } - private static Type parsePrimitiveTypeForNewArray(int arrayType) { - Type type; - - switch (arrayType) { - case 4: type = TYPE_BOOLEAN; break; - case 5: type = TYPE_CHAR; break; - case 6: type = TYPE_FLOAT; break; - case 7: type = TYPE_DOUBLE; break; - case 8: type = TYPE_BYTE; break; - case 9: type = TYPE_SHORT; break; - case 10: type = TYPE_INT; break; - case 11: type = TYPE_LONG; break; - default: assert false; return null; - } - - return type.createType(1); - } - - private Type parseTypeNameForNewArray(String typeName) { - Type type; - - if (typeName.charAt(0) == '[') { - int length = typeName.length(); - char lastChar = typeName.charAt(length - 1); - - switch (lastChar) { - case 'B': type = TYPE_BYTE; break; - case 'C': type = TYPE_CHAR; break; - case 'D': type = TYPE_DOUBLE; break; - case 'F': type = TYPE_FLOAT; break; - case 'I': type = TYPE_INT; break; - case 'J': type = TYPE_LONG; break; - case 'S': type = TYPE_SHORT; break; - case 'Z': type = TYPE_BOOLEAN; break; - case ';': - type = objectTypeMaker.make(typeName); - return type.createType(type.getDimension()+1); - default: - assert false; - return null; - } - - return type.createType(length); - } else { - type = objectTypeMaker.make(typeName); - return type.createType(type.getDimension()+1); - } - } - - private Type parseTypeNameForMultiNewArray(String typeName) { - int lastIndex = typeName.length() - 1; - char lastChar = typeName.charAt(lastIndex); - Type type; - - switch (lastChar) { - case 'B': type = TYPE_BYTE; break; - case 'C': type = TYPE_CHAR; break; - case 'D': type = TYPE_DOUBLE; break; - case 'F': type = TYPE_FLOAT; break; - case 'I': type = TYPE_INT; break; - case 'J': type = TYPE_LONG; break; - case 'S': type = TYPE_SHORT; break; - case 'Z': type = TYPE_BOOLEAN; break; - case ';': - return objectTypeMaker.make(typeName); - default: - assert false; - return null; - } - - return type.createType(lastIndex); - } - /** * @return expression, 'this' or 'super' */ private Expression getFieldInstanceReference(Expression expression, ObjectType ot, String name) { + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable().typeOnLeft(ot); + } + if ((bodyDeclaration.getFieldDeclarations() != null) && (expression.getClass() == ThisExpression.class) && !ot.equals(expression.getType())) { memberVisitor.init(name, null); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 4763cad5..cdf0251c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -971,7 +971,7 @@ protected static boolean reduceJsr(BitSet visited, BasicBlock basicBlock, BitSet BasicBlock branch = basicBlock.getBranch(); boolean reduced = reduce(visited, basicBlock.getNext(), jsrTargets) & reduce(visited, branch, jsrTargets); - if (jsrTargets.get(branch.getIndex())) { + if ((branch.getIndex() >= 0) && jsrTargets.get(branch.getIndex())) { // Reduce JSR int delta = basicBlock.getToOffset() - basicBlock.getFromOffset(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 67479751..9656d436 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -61,22 +61,22 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa String descriptor = field.getDescriptor(); if (descriptor.charAt(descriptor.length() - 1) == ';') { - objectTypeMaker.make(descriptor).accept(populateBlackListNamesVisitor); + objectTypeMaker.makeFromDescriptor(descriptor).accept(populateBlackListNamesVisitor); } blackListNames.add(field.getName()); } } - objectTypeMaker.make(classFile.getInternalTypeName()).accept(populateBlackListNamesVisitor); + objectTypeMaker.makeFromInternalTypeName(classFile.getInternalTypeName()).accept(populateBlackListNamesVisitor); if (classFile.getSuperTypeName() != null) { - objectTypeMaker.make(classFile.getSuperTypeName()).accept(populateBlackListNamesVisitor); + objectTypeMaker.makeFromInternalTypeName(classFile.getSuperTypeName()).accept(populateBlackListNamesVisitor); } if (classFile.getInterfaceTypeNames() != null) { for (String interfaceTypeName : classFile.getInterfaceTypeNames()) { - objectTypeMaker.make(interfaceTypeName).accept(populateBlackListNamesVisitor); + objectTypeMaker.makeFromInternalTypeName(interfaceTypeName).accept(populateBlackListNamesVisitor); } } @@ -95,7 +95,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa if ((method.getAccessFlags() & FLAG_STATIC) == 0) { if (localVariableSet.root(0) == null) { // Local variable missing - localVariableSet.add(0, new ObjectLocalVariable(objectTypeMaker, 0, 0, objectTypeMaker.make(classFile.getInternalTypeName()), "this")); + localVariableSet.add(0, new ObjectLocalVariable(objectTypeMaker, 0, 0, objectTypeMaker.makeFromInternalTypeName(classFile.getInternalTypeName()), "this")); blackListNames.add("this"); } firstVariableIndex = 1; @@ -116,7 +116,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa } else if ((classFile.getOuterClassFile() != null) && ((classFile.getAccessFlags() & FLAG_STATIC) == 0)) { if (localVariableSet.root(1) == null) { // Local variable missing - localVariableSet.add(1, new ObjectLocalVariable(objectTypeMaker, 1, 0, objectTypeMaker.make(classFile.getOuterClassFile().getInternalTypeName()), "this$0")); + localVariableSet.add(1, new ObjectLocalVariable(objectTypeMaker, 1, 0, objectTypeMaker.makeFromInternalTypeName(classFile.getOuterClassFile().getInternalTypeName()), "this$0")); blackListNames.add("this$0"); } } @@ -187,12 +187,12 @@ protected void initLocalVariablesFromAttributes(Method method) { AbstractLocalVariable lv; if (descriptor.charAt(descriptor.length() - 1) == ';') { - lv = new ObjectLocalVariable(objectTypeMaker, index, startPc, objectTypeMaker.make(descriptor), name); + lv = new ObjectLocalVariable(objectTypeMaker, index, startPc, objectTypeMaker.makeFromDescriptor(descriptor), name); } else { int dimension = SignatureParser.countDimension(descriptor); if (dimension == 0) { - lv = new PrimitiveLocalVariable(index, startPc, PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(descriptor), name); + lv = new PrimitiveLocalVariable(index, startPc, PrimitiveType.getPrimitiveType(descriptor.charAt(0)), name); } else { lv = new ObjectLocalVariable(objectTypeMaker, index, startPc, signatureParser.parseTypeSignature(descriptor.substring(dimension)).createType(dimension), name); } @@ -229,7 +229,7 @@ protected void initLocalVariablesFromParameterTypes(ClassFile classFile, List objectTypeCache = new HashMap<>(1024); + protected static final HashMap OBJECT_TYPE_CACHE = new HashMap<>(); + protected static final HashMap OBJECT_PRIMITIVE_TYPE_CACHE = new HashMap<>(); + + static { + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_CLASS.getInternalName(), ObjectType.TYPE_CLASS); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_OBJECT.getInternalName(), ObjectType.TYPE_OBJECT); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_STRING.getInternalName(), ObjectType.TYPE_STRING); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_THROWABLE.getInternalName(), ObjectType.TYPE_THROWABLE); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_EXCEPTION.getInternalName(), ObjectType.TYPE_EXCEPTION); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_RUNTIME_EXCEPTION.getInternalName(), ObjectType.TYPE_RUNTIME_EXCEPTION); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_SYSTEM.getInternalName(), ObjectType.TYPE_SYSTEM); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_STRING_BUILDER.getInternalName(), ObjectType.TYPE_STRING_BUILDER); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_STRING_BUFFER.getInternalName(), ObjectType.TYPE_STRING_BUFFER); + OBJECT_TYPE_CACHE.put(ObjectType.TYPE_THREAD.getInternalName(), ObjectType.TYPE_THREAD); + + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_BOOLEAN.getInternalName(), ObjectType.TYPE_PRIMITIVE_BOOLEAN); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_BYTE.getInternalName(), ObjectType.TYPE_PRIMITIVE_BYTE); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_CHAR.getInternalName(), ObjectType.TYPE_PRIMITIVE_CHAR); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_DOUBLE.getInternalName(), ObjectType.TYPE_PRIMITIVE_DOUBLE); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_FLOAT.getInternalName(), ObjectType.TYPE_PRIMITIVE_FLOAT); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_INT.getInternalName(), ObjectType.TYPE_PRIMITIVE_INT); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_LONG.getInternalName(), ObjectType.TYPE_PRIMITIVE_LONG); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_SHORT.getInternalName(), ObjectType.TYPE_PRIMITIVE_SHORT); + OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_VOID.getInternalName(), ObjectType.TYPE_PRIMITIVE_VOID); + } + + protected HashMap descriptorToObjectTypeCache = new HashMap<>(1024); + protected HashMap internalTypeNameToObjectTypeCache = new HashMap<>(1024); protected HashMap hierarchy = new HashMap<>(1024); protected Loader loader; public ObjectTypeMaker(Loader loader) { this.loader = loader; - - objectTypeCache.put("java/lang/Class", ObjectType.TYPE_CLASS); - objectTypeCache.put("java/lang/Object", ObjectType.TYPE_OBJECT); - objectTypeCache.put("java/lang/String", ObjectType.TYPE_STRING); } - public ObjectType make(String descriptor) { - try { - if (descriptor.charAt(0) == '[') { - ObjectType ot = objectTypeCache.get(descriptor); - - if (ot == null) { - int dimension = 1; + public ObjectType makeFromDescriptor(String descriptor) { + ObjectType ot = descriptorToObjectTypeCache.get(descriptor); - while (descriptor.charAt(dimension) == '[') { - dimension++; - } + if (ot == null) { + if (descriptor.charAt(0) == '[') { + int dimension = 1; - if ((descriptor.charAt(dimension) == 'L') && descriptor.endsWith(";")) { - ot = unsafeMake(descriptor.substring(dimension + 1, descriptor.length() - 1)); - ot = new ObjectType(ot.getInternalName(), ot.getQualifiedName(), ot.getName(), dimension); - objectTypeCache.put(descriptor, ot); - } + while (descriptor.charAt(dimension) == '[') { + dimension++; } - return ot; - } else if ((descriptor.charAt(0) == 'L') && (descriptor.charAt(descriptor.length()-1) == ';')) { - return unsafeMake(descriptor.substring(1, descriptor.length()-1)); + ot = (ObjectType)makeFromDescriptorWithoutBracket(descriptor.substring(dimension)).createType(dimension); } else { - return unsafeMake(descriptor); + ot = makeFromDescriptorWithoutBracket(descriptor); } - } catch (Exception ignore) { - // Class file not found by the system class loader, or invalid class file - return null; + + descriptorToObjectTypeCache.put(descriptor, ot); + } + + return ot; + } + + private ObjectType makeFromDescriptorWithoutBracket(String descriptor) { + ObjectType ot = OBJECT_PRIMITIVE_TYPE_CACHE.get(descriptor); + + if (ot == null) { + ot = makeFromInternalTypeName(descriptor.substring(1, descriptor.length()-1)); } + + return ot; } - private ObjectType unsafeMake(String internalTypeName) throws Exception { - assert (internalTypeName != null) && !internalTypeName.endsWith(";"); + public ObjectType makeFromInternalTypeName(String internalTypeName) { + assert (internalTypeName != null) && !internalTypeName.endsWith(";") : "ObjectTypeMaker.makeFromInternalTypeName(internalTypeName) : invalid internalTypeName"; + + ObjectType ot = OBJECT_TYPE_CACHE.get(internalTypeName); - ObjectType ot = objectTypeCache.get(internalTypeName); + if (ot == null) { + ot = internalTypeNameToObjectTypeCache.get(internalTypeName); + } if (ot == null) { // Search class file with loader, first @@ -86,48 +113,53 @@ private ObjectType unsafeMake(String internalTypeName) throws Exception { return ot; } - private ObjectType loadFromLoader(String internalTypeName) throws Exception { - ObjectType ot = objectTypeCache.get(internalTypeName); + private ObjectType loadFromLoader(String internalTypeName) { + try { + ObjectType ot = internalTypeNameToObjectTypeCache.get(internalTypeName); - if ((ot == null) && loader.canLoad(internalTypeName)) { - String outerTypeName = getOuterTypeName(internalTypeName); + if ((ot == null) && loader.canLoad(internalTypeName)) { + String outerTypeName = getOuterTypeName(internalTypeName); - if (outerTypeName == null) { - int lastSlash = internalTypeName.lastIndexOf('/'); - String qualifiedName = internalTypeName.replace('/', '.'); - String name = qualifiedName.substring(lastSlash + 1); + if (outerTypeName == null) { + int lastSlash = internalTypeName.lastIndexOf('/'); + String qualifiedName = internalTypeName.replace('/', '.'); + String name = qualifiedName.substring(lastSlash + 1); - ot = new ObjectType(internalTypeName, qualifiedName, name); - } else { - ObjectType outerOT = loadFromLoader(outerTypeName); - int index; + ot = new ObjectType(internalTypeName, qualifiedName, name); + } else { + ObjectType outerOT = loadFromLoader(outerTypeName); + int index; - assert outerOT != null; + assert outerOT != null; - if (internalTypeName.length() > outerTypeName.length() + 1) { - index = outerTypeName.length(); - } else { - index = internalTypeName.lastIndexOf('$'); - } + if (internalTypeName.length() > outerTypeName.length() + 1) { + index = outerTypeName.length(); + } else { + index = internalTypeName.lastIndexOf('$'); + } - String innerName = internalTypeName.substring(index + 1); + String innerName = internalTypeName.substring(index + 1); - if (Character.isDigit(innerName.charAt(0))) { - ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerOT); - } else { - String qualifiedName = outerOT.getQualifiedName() + '.' + innerName; - ot = new InnerObjectType(internalTypeName, qualifiedName, innerName, outerOT); + if (Character.isDigit(innerName.charAt(0))) { + ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerOT); + } else { + String qualifiedName = outerOT.getQualifiedName() + '.' + innerName; + ot = new InnerObjectType(internalTypeName, qualifiedName, innerName, outerOT); + } } + + internalTypeNameToObjectTypeCache.put(internalTypeName, ot); } - objectTypeCache.put(internalTypeName, ot); + return ot; + } catch (Exception ignore) { + // Class file not found by the system class loader, or invalid class file + return null; } - - return ot; } private ObjectType loadFromClassLoader(String internalTypeName) { - ObjectType ot = objectTypeCache.get(internalTypeName); + ObjectType ot = internalTypeNameToObjectTypeCache.get(internalTypeName); if (ot == null) { try { @@ -155,7 +187,7 @@ private ObjectType loadFromClassLoader(String internalTypeName) { } catch (ClassNotFoundException ignore) { } - objectTypeCache.put(internalTypeName, ot); + internalTypeNameToObjectTypeCache.put(internalTypeName, ot); } return ot; @@ -171,7 +203,11 @@ private ObjectType create(String internalTypeName) { ObjectType outerSot = create(outerTypeName); String innerName = internalTypeName.substring(outerTypeName.length() + 1); - if (Character.isDigit(innerName.charAt(0))) { + if (innerName.isEmpty()) { + String qualifiedName = internalTypeName.replace('/', '.'); + String name = qualifiedName.substring(lastSlash + 1); + ot = new ObjectType(internalTypeName, qualifiedName, name); + } else if (Character.isDigit(innerName.charAt(0))) { ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerSot); } else { String qualifiedName = outerSot.getQualifiedName() + '.' + innerName; @@ -180,11 +216,10 @@ private ObjectType create(String internalTypeName) { } else { String qualifiedName = internalTypeName.replace('/', '.'); String name = qualifiedName.substring(lastSlash + 1); - ot = new ObjectType(internalTypeName, qualifiedName, name); } - objectTypeCache.put(internalTypeName, ot); + internalTypeNameToObjectTypeCache.put(internalTypeName, ot); return ot; } @@ -389,7 +424,7 @@ private String loadTypeAndApplyFunction(String typeName, String innerTypeName, F } } - private Object[] loadConstants(ClassFileReader reader) throws UTFDataFormatException { + private Object[] loadConstants(ClassFileReader reader) throws Exception { int count = reader.readUnsignedShort(); if (count == 0) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java index f62f4a22..7438d207 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/PrimitiveTypeUtil.java @@ -7,32 +7,25 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; +import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.PrimitiveType; +import org.jd.core.v1.model.javasyntax.type.Type; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; public class PrimitiveTypeUtil { - protected static final PrimitiveType[] descriptorToPrimitiveType = new PrimitiveType['Z' - 'B' + 1]; - - static { - descriptorToPrimitiveType['B' - 'B'] = TYPE_BYTE; - descriptorToPrimitiveType['C' - 'B'] = TYPE_CHAR; - descriptorToPrimitiveType['D' - 'B'] = TYPE_DOUBLE; - descriptorToPrimitiveType['F' - 'B'] = TYPE_FLOAT; - descriptorToPrimitiveType['I' - 'B'] = TYPE_INT; - descriptorToPrimitiveType['J' - 'B'] = TYPE_LONG; - descriptorToPrimitiveType['S' - 'B'] = TYPE_SHORT; - descriptorToPrimitiveType['Z' - 'B'] = TYPE_BOOLEAN; - } - - public static PrimitiveType getPrimitiveTypeFromDescriptor(String descriptor) { + public static Type getPrimitiveTypeFromDescriptor(String descriptor) { int dimension = 0; while (descriptor.charAt(dimension) == '[') { dimension++; } - return descriptorToPrimitiveType[descriptor.charAt(dimension) - 'B'].createType(dimension); + if (dimension == 0) { + return PrimitiveType.getPrimitiveType(descriptor.charAt(dimension)); + } else { + return new ObjectType(descriptor.substring(dimension), dimension); + } } public static PrimitiveType getPrimitiveTypeFromValue(int value) { @@ -54,25 +47,11 @@ public static PrimitiveType getPrimitiveTypeFromValue(int value) { return MAYBE_INT_TYPE; } - public static int getStandardPrimitiveTypeFlags(int flags) { - if ((flags & FLAG_BOOLEAN) != 0) - return FLAG_BOOLEAN; - else if ((flags & FLAG_BYTE) != 0) - return FLAG_BYTE; - else if ((flags & FLAG_CHAR) != 0) - return FLAG_CHAR; - else if ((flags & FLAG_SHORT) != 0) - return FLAG_SHORT; - - return flags; - } - public static PrimitiveType getCommonPrimitiveType(PrimitiveType pt1, PrimitiveType pt2) { - assert (pt1.getDimension() == 0) && (pt2.getDimension() == 0); - return getPrimitiveType(pt1.getFlags() & pt2.getFlags()); + return getPrimitiveTypeFromFlags(pt1.getFlags() & pt2.getFlags()); } - protected static PrimitiveType getPrimitiveType(int flags) { + public static PrimitiveType getPrimitiveTypeFromFlags(int flags) { switch (flags) { case FLAG_BOOLEAN: return TYPE_BOOLEAN; @@ -112,4 +91,18 @@ protected static PrimitiveType getPrimitiveType(int flags) { return null; } -} \ No newline at end of file + + public static Type getPrimitiveTypeFromTag(int tag) { + switch (tag) { + case 4: return TYPE_BOOLEAN; + case 5: return TYPE_CHAR; + case 6: return TYPE_FLOAT; + case 7: return TYPE_DOUBLE; + case 8: return TYPE_BYTE; + case 9: return TYPE_SHORT; + case 10: return TYPE_INT; + case 11: return TYPE_LONG; + default: assert false; return null; + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java index 8dbfb904..6652ed6f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java @@ -60,7 +60,7 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { TypeTypes typeTypes = new TypeTypes(); String internalTypeName = classFile.getInternalTypeName(); - typeTypes.thisType = objectTypeMaker.make(internalTypeName); + typeTypes.thisType = objectTypeMaker.makeFromInternalTypeName(internalTypeName); AttributeSignature attributeSignature = classFile.getAttribute("Signature"); @@ -70,18 +70,18 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { String[] interfaceTypeNames = classFile.getInterfaceTypeNames(); if (! "java/lang/Object".equals(superTypeName)) { - typeTypes.superType = objectTypeMaker.make(superTypeName); + typeTypes.superType = objectTypeMaker.makeFromInternalTypeName(superTypeName); } if (interfaceTypeNames != null) { int length = interfaceTypeNames.length; if (length == 1) { - typeTypes.interfaces = objectTypeMaker.make(interfaceTypeNames[0]); + typeTypes.interfaces = objectTypeMaker.makeFromInternalTypeName(interfaceTypeNames[0]); } else { Types list = new Types(length); for (String interfaceTypeName : interfaceTypeNames) { - list.add(objectTypeMaker.make(interfaceTypeName)); + list.add(objectTypeMaker.makeFromInternalTypeName(interfaceTypeName)); } typeTypes.interfaces = list; } @@ -273,12 +273,12 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { String[] exceptionTypeNames = attributeExceptions.getExceptionTypeNames(); if (exceptionTypeNames.length == 1) { - methodTypes.exceptions = objectTypeMaker.make(exceptionTypeNames[0]); + methodTypes.exceptions = objectTypeMaker.makeFromInternalTypeName(exceptionTypeNames[0]); } else { Types list = new Types(exceptionTypeNames.length); for (String exceptionTypeName : exceptionTypeNames) { - list.add(objectTypeMaker.make(exceptionTypeName)); + list.add(objectTypeMaker.makeFromInternalTypeName(exceptionTypeName)); } methodTypes.exceptions = list; @@ -530,7 +530,7 @@ protected Type parseClassTypeSignature(SignatureReader reader, int dimension) { } String internalTypeName = reader.substring(index); - ObjectType ot = objectTypeMaker.make(internalTypeName); + ObjectType ot = objectTypeMaker.makeFromInternalTypeName(internalTypeName); if (endMarker == '<') { // Skip '<' diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 4a5b1a58..a1b7b596 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -437,7 +437,7 @@ protected void parseTry(WatchDog watchdog, BasicBlock basicBlock, Statements sta finallyStatements.removeLast(); } } else { - stack.push(new NullExpression(objectTypeMaker.make(exceptionHandler.getInternalThrowableName()))); + stack.push(new NullExpression(objectTypeMaker.makeFromInternalTypeName(exceptionHandler.getInternalThrowableName()))); Statements catchStatements = new Statements(); localVariableMaker.pushFrame(catchStatements); @@ -445,7 +445,7 @@ protected void parseTry(WatchDog watchdog, BasicBlock basicBlock, Statements sta BasicBlock bb = exceptionHandler.getBasicBlock(); int lineNumber = bb.getControlFlowGraph().getLineNumber(bb.getFromOffset()); int index = ByteCodeParser.getExceptionLocalVariableIndex(bb); - ObjectType ot = objectTypeMaker.make(exceptionHandler.getInternalThrowableName()); + ObjectType ot = objectTypeMaker.makeFromInternalTypeName(exceptionHandler.getInternalThrowableName()); int offset = bb.getFromOffset(); byte[] code = bb.getControlFlowGraph().getMethod().getAttribute("Code").getCode(); @@ -475,7 +475,7 @@ protected void parseTry(WatchDog watchdog, BasicBlock basicBlock, Statements sta if (exceptionHandler.getOtherInternalThrowableNames() != null) { for (String name : exceptionHandler.getOtherInternalThrowableNames()) { - cc.addType(objectTypeMaker.make(name)); + cc.addType(objectTypeMaker.makeFromInternalTypeName(name)); } } @@ -664,7 +664,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st changeEndLoopToStartLoop(new BitSet(), sub1.getSub1()); subStatements = makeSubStatements(watchdog, sub1.getSub1(), statements, jumps, updateStatements); - assert subStatements.getLast() == ContinueStatement.CONTINUE; + assert subStatements.getLast() == ContinueStatement.CONTINUE : "StatementMaker.parseLoop(...) : unexpected basic block for create a do-while loop"; subStatements.removeLast(); } else { @@ -898,7 +898,7 @@ protected Expression createObjectTypeReferenceDotClassExpression(int lineNumber, } String typeName = ((StringConstantExpression) mie.getParameters()).getString(); - ObjectType ot = objectTypeMaker.make(typeName.replace('.', '/')); + ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName.replace('.', '/')); return new TypeReferenceDotClassExpression(lineNumber, ot); } @@ -932,7 +932,7 @@ protected void replacePreOperatorWithPostOperator(Statements statements) { @SuppressWarnings("unchecked") protected void updateJumpStatements(Statements jumps) { - assert false : "'jumps' list is not empty"; + assert false : "StatementMaker.updateJumpStatements(stmt) : 'jumps' list is not empty"; Iterator iterator = jumps.iterator(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java index 8588694f..dd8f97a1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java @@ -8,7 +8,6 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; import org.jd.core.v1.model.javasyntax.type.*; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; @@ -21,7 +20,7 @@ public String getSuffix() { @Override public void visit(PrimitiveType type) { - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(type.getFlags())) { + switch (type.getJavaPrimitiveFlags()) { case FLAG_BYTE : suffix = "Byte"; break; case FLAG_CHAR : suffix = "Char"; break; case FLAG_DOUBLE : suffix = "Double"; break; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 7d2b3bdb..87171cc6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -407,14 +407,14 @@ public void visit(NewExpression expression) { if (expression.getBodyDeclaration() == null) { ObjectType type = expression.getObjectType(); String internalName = type.getInternalName(); - InterfaceDeclaration declaration = (InterfaceDeclaration)bodyDeclaration.getInnerTypeDeclaration(internalName); + ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); - if (declaration != null) { - cfbd = (ClassFileBodyDeclaration) declaration.getBodyDeclaration(); + if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { + ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; + cfbd = (ClassFileBodyDeclaration)cfcd.getBodyDeclaration(); if ((type.getQualifiedName() == null) && (type.getName() != null)) { // Local class - ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) declaration; cfcd.setFlags(cfcd.getFlags() & (~Declaration.FLAG_SYNTHETIC)); localClassDeclarations.add(cfcd); bodyDeclaration.removeInnerType(internalName); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 767590ca..640d5e91 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -314,7 +314,7 @@ protected BaseExpression updateExpressions(List types, BaseExpression expr Expression updatedParameter = updateExpression(type, parameter); if (updatedParameter.getClass() == IntegerConstantExpression.class) { - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(((PrimitiveType)type).getFlags())) { + switch (((PrimitiveType)type).getJavaPrimitiveFlags()) { case FLAG_BYTE: case FLAG_SHORT: list.set(i, new CastExpression(type, updatedParameter)); @@ -329,7 +329,7 @@ protected BaseExpression updateExpressions(List types, BaseExpression expr Expression updatedParameter = updateExpression(type, (Expression)expressions); if (updatedParameter.getClass() == IntegerConstantExpression.class) { - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(((PrimitiveType)type).getFlags())) { + switch (((PrimitiveType)type).getJavaPrimitiveFlags()) { case FLAG_BYTE: case FLAG_SHORT: expressions = new CastExpression(type, updatedParameter); @@ -361,7 +361,7 @@ protected Expression updateExpression(Type type, Expression expression) { int value = ice.getValue(); int lineNumber = ice.getLineNumber(); - switch (PrimitiveTypeUtil.getStandardPrimitiveTypeFlags(primitiveType.getFlags())) { + switch (primitiveType.getJavaPrimitiveFlags()) { case FLAG_BOOLEAN: return new BooleanExpression(lineNumber, value != 0); case FLAG_CHAR: diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 7bf3fc6a..e334c8c8 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -345,19 +345,19 @@ protected ElementValue loadElementValue(ClassFileReader reader, ConstantPool con ConstantValue constValue = (ConstantValue)constants.getConstant(constValueIndex); return new ElementValuePrimitiveType(type, constValue); case 'e': - int typeNameIndex = reader.readUnsignedShort(); - String typeName = constants.getConstantUtf8(typeNameIndex); + int descriptorIndex = reader.readUnsignedShort(); + String descriptor = constants.getConstantUtf8(descriptorIndex); int constNameIndex = reader.readUnsignedShort(); String constName = constants.getConstantUtf8(constNameIndex); - return new ElementValueEnumConstValue(typeName, constName); + return new ElementValueEnumConstValue(descriptor, constName); case 'c': int classInfoIndex = reader.readUnsignedShort(); String classInfo = constants.getConstantUtf8(classInfoIndex); return new ElementValueClassInfo(classInfo); case '@': int typeIndex = reader.readUnsignedShort(); - typeName = constants.getConstantUtf8(typeIndex); - return new ElementValueAnnotationValue(new Annotation(typeName, loadElementValuePairs(reader, constants))); + descriptor = constants.getConstantUtf8(typeIndex); + return new ElementValueAnnotationValue(new Annotation(descriptor, loadElementValuePairs(reader, constants))); case '[': return new ElementValueArrayValue(loadElementValues(reader, constants)); default: @@ -651,9 +651,9 @@ protected Annotation[] loadAnnotations(ClassFileReader reader, ConstantPool cons Annotation[] annotations = new Annotation[count]; for (int i=0; i Date: Thu, 15 Aug 2019 12:15:04 +0200 Subject: [PATCH 055/211] Fix bug on the declarations of the volatile fields --- build.gradle | 1 + .../jd/core/v1/model/classfile/Constants.java | 4 +- .../javasyntax/declaration/Declaration.java | 4 +- .../visitor/CompilationUnitVisitor.java | 110 ++++++++++-- .../visitor/StatementVisitor.java | 3 + .../jd/core/v1/ClassFileToJavaSourceTest.java | 41 +++-- .../jd/core/v1/JarFileToJavaSourceTest.java | 163 ++++++++++++++++++ src/test/java/org/jd/core/v1/TypeTest.java | 4 +- .../type/visitor/PrintTypeVisitor.java | 3 +- 9 files changed, 299 insertions(+), 34 deletions(-) create mode 100644 src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java diff --git a/build.gradle b/build.gradle index e50044df..a34401a6 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,7 @@ apply plugin: 'com.jfrog.bintray' dependencies { testCompile 'junit:junit:4.12' + testCompile 'org.apache.commons:commons-collections4:4.1' } version='1.0.7' diff --git a/src/main/java/org/jd/core/v1/model/classfile/Constants.java b/src/main/java/org/jd/core/v1/model/classfile/Constants.java index 1028e875..c9062cd0 100644 --- a/src/main/java/org/jd/core/v1/model/classfile/Constants.java +++ b/src/main/java/org/jd/core/v1/model/classfile/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -20,7 +20,7 @@ public interface Constants { int ACC_TRANSITIVE = 0x0020; // . . . . . MR . . int ACC_VOLATILE = 0x0040; // . F . . . . . . int ACC_BRIDGE = 0x0040; // . . M . . . . . - int ACC_STATIC_PHASE = 0x0040; // . . M . . MR . . + int ACC_STATIC_PHASE = 0x0040; // . . . . . MR . . int ACC_TRANSIENT = 0x0080; // . F . . . . . . int ACC_VARARGS = 0x0080; // . . M . . . . . int ACC_NATIVE = 0x0100; // . . M . . . . . diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java index d5e01f5c..8e545613 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -20,7 +20,7 @@ public interface Declaration { int FLAG_TRANSITIVE = 0x0020; // . . . . . MR . . int FLAG_VOLATILE = 0x0040; // . F . . . . . . int FLAG_BRIDGE = 0x0040; // . . M . . . . . - int FLAG_STATIC_PHASE = 0x0040; // . . M . . MR . . + int FLAG_STATIC_PHASE = 0x0040; // . . . . . MR . . int FLAG_TRANSIENT = 0x0080; // . F . . . . . . int FLAG_VARARGS = 0x0080; // . . M . . . . . int FLAG_NATIVE = 0x0100; // . . M . . . . . diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 25d33e69..44dac10c 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -56,7 +56,7 @@ public CompilationUnitVisitor(Loader loader, String mainInternalTypeName, int ma @Override public void visit(AnnotationDeclaration declaration) { - if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & FLAG_SYNTHETIC) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); buildFragmentsForTypeDeclaration(declaration, declaration.getFlags() & ~FLAG_ABSTRACT, ANNOTATION); @@ -209,7 +209,7 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(ClassDeclaration declaration) { - if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & FLAG_SYNTHETIC) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); buildFragmentsForClassOrInterfaceDeclaration(declaration, declaration.getFlags(), CLASS); @@ -336,7 +336,7 @@ public void visit(ConstructorDeclaration declaration) { } // Build tokens for access - buildTokensForAccessFlags(declaration.getFlags()); + buildTokensForMethodAccessFlags(declaration.getFlags()); // Build tokens for type parameters BaseTypeParameter typeParameters = declaration.getTypeParameters(); @@ -465,7 +465,7 @@ public void visit(ElementValuePair reference) { @Override public void visit(EnumDeclaration declaration) { - if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & FLAG_SYNTHETIC) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); buildFragmentsForTypeDeclaration(declaration, declaration.getFlags(), ENUM); @@ -607,7 +607,7 @@ public void visit(ExpressionVariableInitializer declaration) { @Override public void visit(FieldDeclaration declaration) { - if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & FLAG_SYNTHETIC) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_FIELD_BLOCK); tokens = new Tokens(); @@ -623,7 +623,7 @@ public void visit(FieldDeclaration declaration) { } // Build tokens for access - buildTokensForAccessFlags(declaration.getFlags()); + buildTokensForFieldAccessFlags(declaration.getFlags()); declaration.getType().accept(this); tokens.add(StartBlockToken.START_DECLARATION_OR_STATEMENT_BLOCK); @@ -757,7 +757,7 @@ public void visit(InstanceInitializerDeclaration declaration) { @Override public void visit(InterfaceDeclaration declaration) { - if ((declaration.getFlags() & (FLAG_SYNTHETIC | FLAG_BRIDGE)) == 0) { + if ((declaration.getFlags() & FLAG_SYNTHETIC) == 0) { fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_TYPE_BLOCK); buildFragmentsForClassOrInterfaceDeclaration(declaration, declaration.getFlags() & ~FLAG_ABSTRACT, INTERFACE); @@ -1085,7 +1085,7 @@ public void visit(MethodDeclaration declaration) { } // Build tokens for access - buildTokensForAccessFlags(declaration.getFlags()); + buildTokensForMethodAccessFlags(declaration.getFlags()); // Build tokens for type parameters BaseTypeParameter typeParameters = declaration.getTypeParameters(); @@ -1248,7 +1248,7 @@ protected void buildFragmentsForTypeDeclaration(TypeDeclaration declaration, int } // Build tokens for access - buildTokensForAccessFlags(flags); + buildTokensForTypeAccessFlags(flags); tokens.add(keyword); tokens.add(TextToken.SPACE); @@ -1269,21 +1269,50 @@ protected void buildFragmentsForClassOrInterfaceDeclaration(InterfaceDeclaration } } - protected void buildTokensForAccessFlags(int flags) { + protected void buildTokensForTypeAccessFlags(int flags) { if ((flags & FLAG_PUBLIC) != 0) { tokens.add(PUBLIC); tokens.add(TextToken.SPACE); } + if ((flags & FLAG_PROTECTED) != 0) { + tokens.add(PROTECTED); + tokens.add(TextToken.SPACE); + } if ((flags & FLAG_PRIVATE) != 0) { tokens.add(PRIVATE); tokens.add(TextToken.SPACE); } + if ((flags & FLAG_STATIC) != 0) { + tokens.add(STATIC); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_FINAL) != 0) { + tokens.add(FINAL); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_ABSTRACT) != 0) { + tokens.add(ABSTRACT); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_SYNTHETIC) != 0) { + tokens.add(StartMarkerToken.COMMENT); + tokens.add(COMMENT_SYNTHETIC); + tokens.add(EndMarkerToken.COMMENT); + tokens.add(TextToken.SPACE); + } + } + + protected void buildTokensForFieldAccessFlags(int flags) { + if ((flags & FLAG_PUBLIC) != 0) { + tokens.add(PUBLIC); + tokens.add(TextToken.SPACE); + } if ((flags & FLAG_PROTECTED) != 0) { tokens.add(PROTECTED); tokens.add(TextToken.SPACE); } - if ((flags & FLAG_DEFAULT) != 0) { - tokens.add(DEFAULT); + if ((flags & FLAG_PRIVATE) != 0) { + tokens.add(PRIVATE); tokens.add(TextToken.SPACE); } if ((flags & FLAG_STATIC) != 0) { @@ -1294,12 +1323,45 @@ protected void buildTokensForAccessFlags(int flags) { tokens.add(FINAL); tokens.add(TextToken.SPACE); } - if ((flags & FLAG_NATIVE) != 0) { - tokens.add(NATIVE); + if ((flags & FLAG_VOLATILE) != 0) { + tokens.add(VOLATILE); tokens.add(TextToken.SPACE); } - if ((flags & FLAG_ABSTRACT) != 0) { - tokens.add(ABSTRACT); + if ((flags & FLAG_TRANSIENT) != 0) { + tokens.add(TRANSIENT); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_SYNTHETIC) != 0) { + tokens.add(StartMarkerToken.COMMENT); + tokens.add(COMMENT_SYNTHETIC); + tokens.add(EndMarkerToken.COMMENT); + tokens.add(TextToken.SPACE); + } + } + + protected void buildTokensForMethodAccessFlags(int flags) { + if ((flags & FLAG_PUBLIC) != 0) { + tokens.add(PUBLIC); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_PROTECTED) != 0) { + tokens.add(PROTECTED); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_PRIVATE) != 0) { + tokens.add(PRIVATE); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_STATIC) != 0) { + tokens.add(STATIC); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_FINAL) != 0) { + tokens.add(FINAL); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_SYNCHRONIZED) != 0) { + tokens.add(SYNCHRONIZED); tokens.add(TextToken.SPACE); } if ((flags & FLAG_BRIDGE) != 0) { @@ -1308,12 +1370,28 @@ protected void buildTokensForAccessFlags(int flags) { tokens.add(EndMarkerToken.COMMENT); tokens.add(TextToken.SPACE); } + if ((flags & FLAG_NATIVE) != 0) { + tokens.add(NATIVE); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_ABSTRACT) != 0) { + tokens.add(ABSTRACT); + tokens.add(TextToken.SPACE); + } + if ((flags & FLAG_STRICT) != 0) { + tokens.add(STRICT); + tokens.add(TextToken.SPACE); + } if ((flags & FLAG_SYNTHETIC) != 0) { tokens.add(StartMarkerToken.COMMENT); tokens.add(COMMENT_SYNTHETIC); tokens.add(EndMarkerToken.COMMENT); tokens.add(TextToken.SPACE); } + if ((flags & FLAG_DEFAULT) != 0) { + tokens.add(DEFAULT); + tokens.add(TextToken.SPACE); + } } protected class AnnotationVisitor extends AbstractJavaSyntaxVisitor { diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java index ac0a7f3b..f5f83de3 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java @@ -37,10 +37,13 @@ public class StatementVisitor extends ExpressionVisitor { public static final KeywordToken FOR = new KeywordToken("for"); public static final KeywordToken IF = new KeywordToken("if"); public static final KeywordToken RETURN = new KeywordToken("return"); + public static final KeywordToken STRICT = new KeywordToken("strictfp"); public static final KeywordToken SYNCHRONIZED = new KeywordToken("synchronized"); public static final KeywordToken SWITCH = new KeywordToken("switch"); public static final KeywordToken THROW = new KeywordToken("throw"); + public static final KeywordToken TRANSIENT = new KeywordToken("transient"); public static final KeywordToken TRY = new KeywordToken("try"); + public static final KeywordToken VOLATILE = new KeywordToken("volatile"); public static final KeywordToken WHILE = new KeywordToken("while"); public StatementVisitor(Loader loader, String mainInternalTypeName, int majorVersion, ImportsFragment importsFragment) { diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 97cb1c80..1d8da050 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -24,6 +24,7 @@ import org.junit.Test; import java.io.InputStream; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -1117,8 +1118,11 @@ public void testJdk150AnonymousClass() throws Exception { assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}"))); + assertTrue(CompilerUtil.compile( + "1.5", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") + )); } @Test @@ -1587,6 +1591,8 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); + // TODO assertTrue(source.matches(PatternMaker.make("/* 217:", "inCatch1();"))); + assertTrue(source.indexOf("/* 888: 888 */") != -1); assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); @@ -1599,6 +1605,9 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + + System.out.println(ClassFileToJavaSourceTest.class.getProtectionDomain().getCodeSource().getLocation().getPath()); + System.out.println(System.getProperty("java.class.path")); } @Test @@ -1943,11 +1952,14 @@ public void testJdk170AnnotatedClass() throws Exception { assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), new JavaSourceFileObject("org/jd/core/test/annotation/Author", "package org.jd.core.test.annotation; public @interface Author {Name value(); Name[] contributors() default {};}"), new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String salutation() default \"\"; String value(); String last() default \"\";}"), new JavaSourceFileObject("org/jd/core/test/annotation/Quality", "package org.jd.core.test.annotation; public @interface Quality {enum Level {LOW,MIDDLE,HIGH}; Level value();}"), - new JavaSourceFileObject("org/jd/core/test/annotation/Value", "package org.jd.core.test.annotation; public @interface Value {boolean z() default true; byte b() default 1; short s() default 1; int i() default 1; long l() default 1L; float f() default 1.0F; double d() default 1.0D; String str() default \"str\"; Class clazz() default Object.class;}"))); + new JavaSourceFileObject("org/jd/core/test/annotation/Value", "package org.jd.core.test.annotation; public @interface Value {boolean z() default true; byte b() default 1; short s() default 1; int i() default 1; long l() default 1L; float f() default 1.0F; double d() default 1.0D; String str() default \"str\"; Class clazz() default Object.class;}") + )); } @Test @@ -2003,8 +2015,11 @@ public void testJdk170AnonymousClass() throws Exception { assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}"))); + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") + )); } @Test @@ -2054,8 +2069,11 @@ public void testJdk170GenericClass() throws Exception { assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/AnnotatedClass", "package org.jd.core.test; public class AnnotatedClass {}"))); + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/AnnotatedClass", "package org.jd.core.test; public class AnnotatedClass {}") + )); } @Test @@ -2090,8 +2108,11 @@ public void testJdk170AnnotationAuthor() throws Exception { assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}"))); + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") + )); } @Test diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java new file mode 100644 index 00000000..75374789 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.jd.core.v1.util.DefaultList; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class JarFileToJavaSourceTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testCommonsCollections4() throws Exception { + // Test 'commons-collections4-4.1.jar' + test(org.apache.commons.collections4.CollectionUtils.class); + } + + protected void test(Class clazz) throws Exception { + test(new FileInputStream(Paths.get(clazz.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile())); + } + + protected void test(InputStream inputStream) throws Exception { + long fileCounter = 0; + long exceptionCounter = 0; + long assertFailedCounter = 0; + long recompilationFailedCounter = 0; + + try (InputStream is = inputStream) { + ZipLoader loader = new ZipLoader(is); + CounterPrinter printer = new CounterPrinter(); + HashMap statistics = new HashMap<>(); + + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", Collections.singletonMap("realignLineNumbers", Boolean.TRUE)); + + for (String path : loader.getMap().keySet()) { + if (path.endsWith(".class") && (path.indexOf('$') == -1)) { + String internalTypeName = path.substring(0, path.length() - 6); // 6 = ".class".length() + message.setHeader("mainInternalTypeName", internalTypeName); + printer.init(); + + fileCounter++; + + try { + // Decompile class + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + } catch (AssertionError e) { + String msg = (e.getMessage() == null) ? "" : e.getMessage(); + Integer counter = statistics.get(msg); + statistics.put(msg, (counter == null) ? 1 : counter + 1); + assertFailedCounter++; + } catch (Throwable t) { + String msg = t.getMessage() == null ? t.getClass().toString() : t.getMessage(); + Integer counter = statistics.get(msg); + statistics.put(msg, (counter == null) ? 1 : counter + 1); + exceptionCounter++; + } + + // Recompile source + String source = printer.toString(); + + if (!CompilerUtil.compile("1.8", new JavaSourceFileObject(internalTypeName, source))) { + recompilationFailedCounter++; + } + } + } + + System.out.println("Counters:"); + System.out.println(" fileCounter =" + fileCounter); + System.out.println(" class+innerClassCounter =" + printer.classCounter); + System.out.println(" methodCounter =" + printer.methodCounter); + System.out.println(" exceptionCounter =" + exceptionCounter); + System.out.println(" assertFailedCounter =" + assertFailedCounter); + System.out.println(" errorInMethodCounter =" + printer.errorInMethodCounter); + System.out.println(" accessCounter =" + printer.accessCounter); + System.out.println(" recompilationFailed =" + recompilationFailedCounter); + System.out.println("Percentages:"); + System.out.println(" % exception =" + (exceptionCounter * 100F / fileCounter)); + System.out.println(" % assert failed =" + (assertFailedCounter * 100F / fileCounter)); + System.out.println(" % error in method =" + (printer.errorInMethodCounter * 100F / printer.methodCounter)); + System.out.println(" % recompilation failed =" + (recompilationFailedCounter * 100F / fileCounter)); + + System.out.println("Errors:"); + DefaultList stats = new DefaultList<>(); + for (Map.Entry stat : statistics.entrySet()) { + stats.add(" " + stat.getValue() + " \t: " + stat.getKey()); + } + stats.sort((s1, s2) -> Integer.parseInt(s2.substring(0, 5).trim()) - Integer.parseInt(s1.substring(0, 5).trim())); + for (String stat : stats) { + System.out.println(stat); + } + + assertTrue(exceptionCounter == 0); + assertTrue(assertFailedCounter == 0); + // TODO assertTrue(recompilationFailedCounter == 0); + } + } + + protected static class CounterPrinter extends PlainTextPrinter { + public long classCounter = 0; + public long methodCounter = 0; + public long errorInMethodCounter = 0; + public long accessCounter = 0; + + public void printText(String text) { + if (text != null) { + if ("// Byte code:".equals(text) || text.startsWith("/* monitor enter ") || text.startsWith("/* monitor exit ")) { + errorInMethodCounter++; + } + } + super.printText(text); + } + + public void printDeclaration(int type, String internalTypeName, String name, String descriptor) { + if (type == TYPE) classCounter++; + if ((type == METHOD) || (type == CONSTRUCTOR)) methodCounter++; + super.printDeclaration(type, internalTypeName, name, descriptor); + } + + public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) { + if ((name != null) && name.startsWith("access$")) { + accessCounter++; + } + super.printReference(type, internalTypeName, name, descriptor, ownerInternalName); + } + } +} diff --git a/src/test/java/org/jd/core/v1/TypeTest.java b/src/test/java/org/jd/core/v1/TypeTest.java index 3fc26004..4aa75ca1 100644 --- a/src/test/java/org/jd/core/v1/TypeTest.java +++ b/src/test/java/org/jd/core/v1/TypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -37,7 +37,7 @@ public void testSimpleClassOrInterfaceType2() throws Exception { new ArrayTypeArguments( Arrays.asList( scoit1, - new UnknownTypeArgument(), + new WildcardTypeArgument(), new WildcardSuperTypeArgument(scoit1), new WildcardExtendsTypeArgument(scoit1) ) diff --git a/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java index f61b1a7d..b38f956d 100644 --- a/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java +++ b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java @@ -8,7 +8,6 @@ package org.jd.core.v1.services.javasyntax.type.visitor; import org.jd.core.v1.model.javasyntax.type.*; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import java.util.List; @@ -122,7 +121,7 @@ public void visit(TypeParameters types) { } @Override - public void visit(UnknownTypeArgument type) { + public void visit(WildcardTypeArgument type) { sb.append('?'); } From e80f641290a31b553860acdcc16a1058ce8a6e0e Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 12:17:22 +0200 Subject: [PATCH 056/211] Improve generic variable declarations in 'for' loops --- .../util/LoopStatementMaker.java | 79 +++++-------------- 1 file changed, 20 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index 332b0f1b..09fa957e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,15 +7,18 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; -import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileBreakContinueStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForEachStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.CreateTypeFromTypeArgumentVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.RemoveLastContinueStatementVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchLocalVariableReferenceVisitor; @@ -600,13 +603,13 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker } // Check if 'i$' is not used in sub-statements - SearchLocalVariableReferenceVisitor visitor = new SearchLocalVariableReferenceVisitor(syntheticIterator); + SearchLocalVariableReferenceVisitor visitor1 = new SearchLocalVariableReferenceVisitor(syntheticIterator); for (int i=1, len=subStatements.size(); i Date: Thu, 15 Aug 2019 12:24:44 +0200 Subject: [PATCH 057/211] Refactoring : rename 'UnknownTypeArgument' to 'WildcardTypeArgument' --- .../v1/model/javasyntax/type/AbstractNopTypeVisitor.java | 4 ++-- .../v1/model/javasyntax/type/AbstractTypeVisitor.java | 4 ++-- .../jd/core/v1/model/javasyntax/type/TypeVisitor.java | 4 ++-- ...nknownTypeArgument.java => WildcardTypeArgument.java} | 9 +++++++-- .../classfiletojavasyntax/model/localvariable/Frame.java | 2 +- .../classfiletojavasyntax/util/SignatureParser.java | 4 ++-- .../javasyntaxtojavafragment/visitor/TypeVisitor.java | 2 +- 7 files changed, 17 insertions(+), 12 deletions(-) rename src/main/java/org/jd/core/v1/model/javasyntax/type/{UnknownTypeArgument.java => WildcardTypeArgument.java} (64%) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java index aa3a2a80..81a2147e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -21,5 +21,5 @@ public abstract class AbstractNopTypeVisitor implements TypeVisitor { @Override public void visit(TypeParameterWithTypeBounds type) {} @Override public void visit(TypeParameters types) {} @Override public void visit(GenericType type) {} - @Override public void visit(UnknownTypeArgument type) {} + @Override public void visit(WildcardTypeArgument type) {} } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java index c8938a12..363bbf1c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -81,7 +81,7 @@ public void visit(TypeParameters list) { public void visit(GenericType type) {} @Override - public void visit(UnknownTypeArgument type) {} + public void visit(WildcardTypeArgument type) {} protected void safeAccept(TypeVisitable type) { if (type != null) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java index bad81646..e43f4d7f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -21,5 +21,5 @@ public interface TypeVisitor { void visit(TypeParameters types); void visit(WildcardSuperTypeArgument type); void visit(GenericType type); - void visit(UnknownTypeArgument type); + void visit(WildcardTypeArgument type); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/UnknownTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java similarity index 64% rename from src/main/java/org/jd/core/v1/model/javasyntax/type/UnknownTypeArgument.java rename to src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java index e44878a7..45292b8f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/UnknownTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,10 +7,15 @@ package org.jd.core.v1.model.javasyntax.type; -public class UnknownTypeArgument implements TypeArgument { +public class WildcardTypeArgument implements TypeArgument { @Override public void accept(TypeVisitor visitor) { visitor.visit(this); } + + @Override + public String toString() { + return "Wildcard{?}"; + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 8fe3ff50..e8077f4d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -856,7 +856,7 @@ protected void generate(Type type) { @Override public void visit(TypeParameterWithTypeBounds type) {} @Override public void visit(TypeParameters types) {} @Override public void visit(WildcardSuperTypeArgument type) {} - @Override public void visit(UnknownTypeArgument type) {} + @Override public void visit(WildcardTypeArgument type) {} } protected static class AbstractLocalVariableComparator implements Comparator { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java index 6652ed6f..c1b5afba 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java @@ -27,7 +27,7 @@ * http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html */ public class SignatureParser { - protected static final UnknownTypeArgument UNKNOWN_TYPE_ARGUMENT = new UnknownTypeArgument(); + protected static final WildcardTypeArgument WILDCARD_TYPE_ARGUMENT = new WildcardTypeArgument(); protected HashMap methodTypesCache = new HashMap<>(1024); protected HashMap typeCache = new HashMap<>(1024); @@ -681,7 +681,7 @@ protected TypeArgument parseTypeArgument(SignatureReader reader) { case '-': return new WildcardSuperTypeArgument(parseReferenceTypeSignature(reader)); case '*': - return UNKNOWN_TYPE_ARGUMENT; + return WILDCARD_TYPE_ARGUMENT; default: // Unread 'c' reader.index--; diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index adcc4179..65039744 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -209,7 +209,7 @@ public void visit(GenericType type) { } @Override - public void visit(UnknownTypeArgument type) { + public void visit(WildcardTypeArgument type) { tokens.add(TextToken.QUESTIONMARK); } From b9db633ffd0fbbfedc136556669456a49530b21c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 12:27:09 +0200 Subject: [PATCH 058/211] Improve 'CompilerUtil' --- .../org/jd/core/v1/compiler/CompilerUtil.java | 64 ++++++++++++++++--- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/jd/core/v1/compiler/CompilerUtil.java b/src/test/java/org/jd/core/v1/compiler/CompilerUtil.java index 6eeee267..646891d7 100644 --- a/src/test/java/org/jd/core/v1/compiler/CompilerUtil.java +++ b/src/test/java/org/jd/core/v1/compiler/CompilerUtil.java @@ -11,34 +11,82 @@ import java.io.File; import java.io.StringWriter; import java.util.Arrays; +import java.util.List; public class CompilerUtil { protected static final File DESTINATION_DIRECTORY = new File("build/test-recompiled"); protected static final String DESTINATION_DIRECTORY_PATH = DESTINATION_DIRECTORY.getAbsolutePath(); - public static boolean compile(String javaVersion, JavaFileObject... JavaFileObjects) throws Exception { + public static boolean compile(String preferredJavaVersion, JavaFileObject... javaFileObjects) throws Exception { boolean compilationSuccess = false; + String javaVersion = getJavaVersion(preferredJavaVersion); DESTINATION_DIRECTORY.mkdirs(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StringWriter writer = new StringWriter(); DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + List options = Arrays.asList("-source", javaVersion, "-target", javaVersion, "-d", DESTINATION_DIRECTORY_PATH, "-cp", System.getProperty("java.class.path")); + List compilationUnits = Arrays.asList(javaFileObjects); try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) { - Iterable options = Arrays.asList("-source", javaVersion, "-target", javaVersion, "-d", DESTINATION_DIRECTORY_PATH); - Iterable compilationUnits = Arrays.asList(JavaFileObjects); compilationSuccess = compiler.getTask(writer, fileManager, diagnostics, options, null, compilationUnits).call(); - for (Diagnostic d : diagnostics.getDiagnostics()) { - if (d.getLineNumber() > 0) { - System.err.print(String.format("%-7s - line %-4d- %s%n", d.getKind(), d.getLineNumber(), d.getMessage(null))); - } else { - System.err.print(String.format("%-7s - - %s%n", d.getKind(), d.getMessage(null))); + if (!diagnostics.getDiagnostics().isEmpty()) { + StringBuilder sb = new StringBuilder(); + + for (Diagnostic d : diagnostics.getDiagnostics()) { + switch (d.getKind()) { + case NOTE: + case WARNING: + break; + default: + if (d.getLineNumber() > 0) { + sb.append(String.format("%-7s - line %-4d- %s%n", d.getKind(), d.getLineNumber(), d.getMessage(null))); + } else { + sb.append(String.format("%-7s - - %s%n", d.getKind(), d.getMessage(null))); + } + break; + } + } + + if (sb.length() > 0) { + System.err.println(compilationUnits.get(0).getName()); + System.err.print(sb.toString()); } } } return compilationSuccess; } + + private static String getJavaVersion(String preferredJavaVersion) { + int numericSystemJavaVersion = parseJavaVersion(System.getProperty("java.version")); + + if (numericSystemJavaVersion <= 8) { + return preferredJavaVersion; + } else { + int numericPreferredJavaVersion = parseJavaVersion(preferredJavaVersion); + + if (numericPreferredJavaVersion < 6) { + return "1.6"; + } else { + return preferredJavaVersion; + } + } + } + + private static int parseJavaVersion(String javaVersion) { + if(javaVersion.startsWith("1.")) { + javaVersion = javaVersion.substring(2, 3); + } else { + int index = javaVersion.indexOf("."); + + if(index != -1) { + javaVersion = javaVersion.substring(0, index); + } + } + + return Integer.parseInt(javaVersion); + } } From cb0dad6afc0c3af9fdd0d6c41a78a6ffa48fbb91 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 12:32:14 +0200 Subject: [PATCH 059/211] Refactor LoopStatementMaker --- .../CreateTypeFromTypeArgumentVisitor.java | 33 ++++++++++ .../RemoveLastContinueStatementVisitor.java | 65 +++++++++++++++++++ .../SearchWildcardTypeArgumentVisitor.java | 50 ++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveLastContinueStatementVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchWildcardTypeArgumentVisitor.java diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java new file mode 100644 index 00000000..923d2d51 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +public class CreateTypeFromTypeArgumentVisitor extends AbstractNopTypeVisitor { + protected Type type; + + public CreateTypeFromTypeArgumentVisitor() { + init(); + } + + public void init() { + type = null; + } + + public Type getType() { + return type; + } + + @Override public void visit(WildcardExtendsTypeArgument type) { this.type = type.getType(); } + @Override public void visit(WildcardSuperTypeArgument type) { this.type = type.getType(); } + @Override public void visit(PrimitiveType type) { this.type = type; } + @Override public void visit(ObjectType type) { this.type = type; } + @Override public void visit(InnerObjectType type) { this.type = type; } + @Override public void visit(GenericType type) { this.type = type; } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveLastContinueStatementVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveLastContinueStatementVisitor.java new file mode 100644 index 00000000..1abdd92a --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveLastContinueStatementVisitor.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.statement.*; + +public class RemoveLastContinueStatementVisitor extends AbstractJavaSyntaxVisitor { + @Override + public void visit(Statements list) { + if (! list.isEmpty()) { + Statement last = (Statement)list.getLast(); + + if (last.getClass() == ContinueStatement.class) { + list.removeLast(); + visit(list); + } else { + last.accept(this); + } + } + } + + @Override public void visit(IfElseStatement statement) { + safeAccept(statement.getStatements()); + statement.getElseStatements().accept(this); + } + + @Override public void visit(TryStatement statement) { + statement.getTryStatements().accept(this); + safeAcceptListStatement(statement.getCatchClauses()); + safeAccept(statement.getFinallyStatements()); + } + + @Override public void visit(SwitchStatement statement) { acceptListStatement(statement.getBlocks()); } + @Override public void visit(SwitchStatement.LabelBlock statement) { statement.getStatements().accept(this); } + @Override public void visit(SwitchStatement.MultiLabelsBlock statement) { statement.getStatements().accept(this); } + @Override public void visit(IfStatement statement) { safeAccept(statement.getStatements()); } + @Override public void visit(SynchronizedStatement statement) { safeAccept(statement.getStatements()); } + @Override public void visit(TryStatement.CatchClause statement) { safeAccept(statement.getStatements()); } + + @Override public void visit(DoWhileStatement statement) {} + @Override public void visit(ForEachStatement statement) {} + @Override public void visit(ForStatement statement) {} + @Override public void visit(WhileStatement statement) {} + @Override public void visit(AssertStatement statement) {} + @Override public void visit(BreakStatement statement) {} + @Override public void visit(ByteCodeStatement statement) {} + @Override public void visit(CommentStatement statement) {} + @Override public void visit(ContinueStatement statement) {} + @Override public void visit(ExpressionStatement statement) {} + @Override public void visit(LabelStatement statement) {} + @Override public void visit(LambdaExpressionStatement statement) {} + @Override public void visit(LocalVariableDeclarationStatement statement) {} + @Override public void visit(ReturnExpressionStatement statement) {} + @Override public void visit(ReturnStatement statement) {} + @Override public void visit(SwitchStatement.ExpressionLabel statement) {} + @Override public void visit(ThrowStatement statement) {} + @Override public void visit(TypeDeclarationStatement statement) {} + @Override public void visit(TryStatement.Resource statement) {} +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchWildcardTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchWildcardTypeArgumentVisitor.java new file mode 100644 index 00000000..cd3e661c --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchWildcardTypeArgumentVisitor.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.AbstractTypeVisitor; +import org.jd.core.v1.model.javasyntax.type.WildcardExtendsTypeArgument; +import org.jd.core.v1.model.javasyntax.type.WildcardSuperTypeArgument; +import org.jd.core.v1.model.javasyntax.type.WildcardTypeArgument; + +public class SearchWildcardTypeArgumentVisitor extends AbstractTypeVisitor { + protected boolean wildcardFound; + protected boolean wildcardSuperOrExtendsTypeFound; + + public SearchWildcardTypeArgumentVisitor() { + init(); + } + + public void init() { + wildcardFound = false; + wildcardSuperOrExtendsTypeFound = false; + } + + public boolean containsWildcard() { + return wildcardFound; + } + + public boolean containsWildcardSuperOrExtendsType() { + return wildcardSuperOrExtendsTypeFound; + } + + @Override + public void visit(WildcardTypeArgument type) { + wildcardFound = true; + } + + @Override + public void visit(WildcardExtendsTypeArgument type) { + wildcardSuperOrExtendsTypeFound = true; + } + + @Override + public void visit(WildcardSuperTypeArgument type) { + wildcardSuperOrExtendsTypeFound = true; + } +} From a97d78f1fee33424941df1084a049a6914369ebe Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 12:34:36 +0200 Subject: [PATCH 060/211] Simplification --- .../javasyntax/expression/SuperExpression.java | 13 ++++--------- .../model/javasyntax/expression/ThisExpression.java | 13 ++++--------- .../classfiletojavasyntax/util/StatementMaker.java | 6 +++--- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java index c42a9371..10788db1 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,25 +7,20 @@ package org.jd.core.v1.model.javasyntax.expression; -import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; public class SuperExpression extends AbstractLineNumberExpression { - protected ObjectType type; + protected Type type; - public SuperExpression(ObjectType type) { + public SuperExpression(Type type) { this.type = type; } - public SuperExpression(int lineNumber, ObjectType type) { + public SuperExpression(int lineNumber, Type type) { super(lineNumber); this.type = type; } - public ObjectType getObjectType() { - return type; - } - @Override public Type getType() { return type; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java index c8b92af5..eb626b15 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,28 +7,23 @@ package org.jd.core.v1.model.javasyntax.expression; -import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; public class ThisExpression extends AbstractLineNumberExpression { - protected ObjectType type; + protected Type type; protected boolean explicit; - public ThisExpression(ObjectType type) { + public ThisExpression(Type type) { this.type = type; this.explicit = true; } - public ThisExpression(int lineNumber, ObjectType type) { + public ThisExpression(int lineNumber, Type type) { super(lineNumber); this.type = type; this.explicit = true; } - public ObjectType getObjectType() { - return type; - } - @Override public Type getType() { return type; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index a1b7b596..13ef828f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -880,7 +880,7 @@ protected Expression createObjectTypeReferenceDotClassExpression(int lineNumber, for (ClassFileFieldDeclaration field : bodyDeclaration.getFieldDeclarations()) { field.getFieldDeclarators().accept(memberVisitor); - if (memberVisitor.isFound()) { + if (memberVisitor.found()) { field.setFlags(field.getFlags() | Constants.ACC_SYNTHETIC); break; } @@ -891,7 +891,7 @@ protected Expression createObjectTypeReferenceDotClassExpression(int lineNumber, for (ClassFileConstructorOrMethodDeclaration member : bodyDeclaration.getMethodDeclarations()) { member.accept(memberVisitor); - if (memberVisitor.isFound()) { + if (memberVisitor.found()) { member.setFlags(member.getFlags() | Constants.ACC_SYNTHETIC); break; } @@ -964,7 +964,7 @@ public void init(String name) { this.found = false; } - public boolean isFound() { + public boolean found() { return found; } From 1fe723a67ba322103a4a3152631befe25a9f9f9c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 12:42:40 +0200 Subject: [PATCH 061/211] Improve recognition of local variables --- .../v1/model/javasyntax/type/ObjectType.java | 12 +- .../localvariable/GenericLocalVariable.java | 7 +- .../localvariable/ObjectLocalVariable.java | 37 +++--- .../util/ByteCodeParser.java | 105 +++++++++++------- .../visitor/InitInnerClassVisitor.java | 32 ++++-- .../java/org/jd/core/v1/loader/ZipLoader.java | 2 + .../jd/core/v1/printer/PlainTextPrinter.java | 6 + 7 files changed, 133 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index 01f51687..25ee49b6 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -166,12 +166,22 @@ public boolean equals(Object o) { if (dimension != that.dimension) return false; if (!internalName.equals(that.internalName)) return false; - return true; + if ("java/lang/Class".equals(internalName)) { + boolean wildcard1 = (typeArguments == null) || (typeArguments.getClass() == WildcardTypeArgument.class); + boolean wildcard2 = (that.typeArguments == null) || (that.typeArguments.getClass() == WildcardTypeArgument.class); + + if (wildcard1 && wildcard2) { + return true; + } + } + + return typeArguments != null ? typeArguments.equals(that.typeArguments) : that.typeArguments == null; } @Override public int hashCode() { int result = internalName.hashCode(); + result = 31 * result + (typeArguments != null ? typeArguments.hashCode() : 0); result = 31 * result + dimension; return result; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java index 473272af..db12067e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java @@ -43,11 +43,14 @@ public String toString() { return "GenericLocalVariable{" + type + ", index=" + index + "}"; } - @Override public boolean isAssignableFrom(Type otherType) { return true; } + @Override public boolean isAssignableFrom(Type otherType) { + return type.equals(otherType); + } + @Override public void typeOnRight(Type type) {} @Override public void typeOnLeft(Type type) {} - @Override public boolean isAssignableFrom(AbstractLocalVariable variable) { return true; } + @Override public boolean isAssignableFrom(AbstractLocalVariable variable) { return isAssignableFrom(variable.getType()); } @Override public void variableOnRight(AbstractLocalVariable variable) {} @Override public void variableOnLeft(AbstractLocalVariable variable) {} } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index b1066223..3fbec761 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -98,23 +98,28 @@ public void typeOnRight(Type type) { } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { assert !this.type.isPrimitive() && !type.isPrimitive() : "ObjectLocalVariable.typeOnRight(type) : unexpected type"; - if (this.type.isObject() && type.isObject()) { - ObjectType thisObjectType = (ObjectType)this.type; - ObjectType otherObjectType = (ObjectType)type; - - if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { - if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { - // Keep type, update type arguments - this.type = otherObjectType; - fireChangeEvent(); - } - } else if (objectTypeMaker.isAssignable(thisObjectType, otherObjectType)) { - // Assignable types - if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { - // Keep type, update type arguments - this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); - fireChangeEvent(); + if (this.type.isObject()) { + if (type.isObject()) { + ObjectType thisObjectType = (ObjectType) this.type; + ObjectType otherObjectType = (ObjectType) type; + + if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = otherObjectType; + fireChangeEvent(); + } + } else if (objectTypeMaker.isAssignable(thisObjectType, otherObjectType)) { + // Assignable types + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); + fireChangeEvent(); + } } + } else if (type.isGeneric() && (this.type == TYPE_OBJECT)) { + this.type = type; + fireChangeEvent(); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index cb9724c7..2477546f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -30,9 +30,9 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileMonitorEnterStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileMonitorExitStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.GenericLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.PrimitiveLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchWildcardTypeArgumentVisitor; import org.jd.core.v1.util.DefaultList; import org.jd.core.v1.util.DefaultStack; @@ -59,6 +59,7 @@ public class ByteCodeParser { private Type returnedType; private MemberVisitor memberVisitor = new MemberVisitor(); private SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); + private SearchWildcardTypeArgumentVisitor searchWildcardTypeArgumentVisitor = new SearchWildcardTypeArgumentVisitor(); public ByteCodeParser( ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, LocalVariableMaker localVariableMaker, @@ -147,7 +148,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau localVariable = localVariableMaker.getLocalVariable(i, offset); if ((i == 0) && ((method.getAccessFlags() & ACC_STATIC) == 0)) { - stack.push(new ThisExpression(lineNumber, (ObjectType)localVariable.getType())); + stack.push(new ThisExpression(lineNumber, localVariable.getType())); } else { stack.push(new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable)); } @@ -172,7 +173,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau localVariable = localVariableMaker.getLocalVariable(0, offset); if ((method.getAccessFlags() & ACC_STATIC) == 0) { - stack.push(new ThisExpression(lineNumber, (ObjectType)localVariable.getType())); + stack.push(new ThisExpression(lineNumber, localVariable.getType())); } else { stack.push(new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable)); } @@ -752,7 +753,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau if (expression1.getClass() == NewExpression.class) { ((NewExpression)expression1).setDescriptorAndParameters(descriptor, parameters); - } else if (expression1.getType().equals(ot)) { + } else if (ot.getInternalName().equals(((ObjectType)expression1.getType()).getInternalName())) { statements.add(new ExpressionStatement(new ConstructorInvocationExpression(lineNumber, ot, descriptor, parameters))); } else { statements.add(new ExpressionStatement(new SuperConstructorInvocationExpression(lineNumber, ot, descriptor, parameters))); @@ -921,11 +922,7 @@ private BaseExpression getParameters(Statements statements, DefaultStack statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { + private void parseASTORE(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); Expression oldValueRef = valueRef; if (valueRef.getClass() == NewArray.class) { valueRef = NewArrayMaker.make(statements, (NewArray)valueRef); } - if ((localVariable.getClass() == GenericLocalVariable.class) && !localVariable.getType().equals(valueRef.getType())) { + + if (!localVariable.isAssignableFrom(valueRef.getType())) { valueRef = new CastExpression(valueRef.getLineNumber(), localVariable.getType(), valueRef); } + if (oldValueRef != valueRef) { stack.replace(oldValueRef, valueRef); } @@ -1602,11 +1597,7 @@ private static void parseIF(DefaultStack stack, int lineNumber, Basi @SuppressWarnings("unchecked") private void parseXRETURN(Statements statements, DefaultStack stack, int lineNumber) { - Expression valueRef = stack.pop(); - - if (valueRef.getClass() == ClassFileLocalVariableReferenceExpression.class) { - ((ClassFileLocalVariableReferenceExpression)valueRef).getLocalVariable().typeOnLeft(returnedType); - } + Expression valueRef = checkLocalVariableReferenceExpression(stack.pop(), returnedType); if (valueRef.getClass() == NewArray.class) { valueRef = NewArrayMaker.make(statements, (NewArray)valueRef); @@ -1909,17 +1900,16 @@ private static void reduceIntegerLocalVariableType(Expression expression) { * @return expression, 'this' or 'super' */ private Expression getFieldInstanceReference(Expression expression, ObjectType ot, String name) { - if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { - ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable().typeOnLeft(ot); - } - - if ((bodyDeclaration.getFieldDeclarations() != null) && (expression.getClass() == ThisExpression.class) && !ot.equals(expression.getType())) { - memberVisitor.init(name, null); - - for (ClassFileFieldDeclaration field : bodyDeclaration.getFieldDeclarations()) { - field.getFieldDeclarators().accept(memberVisitor); - if (memberVisitor.isFound()) { - return new SuperExpression(expression.getLineNumber(), ((ThisExpression) expression).getObjectType()); + if ((bodyDeclaration.getFieldDeclarations() != null) && (expression.getClass() == ThisExpression.class)) { + String internalName = ((ObjectType)expression.getType()).getInternalName(); + + if (!ot.getInternalName().equals(internalName)) { + memberVisitor.init(name, null); + for (ClassFileFieldDeclaration field : bodyDeclaration.getFieldDeclarations()) { + field.getFieldDeclarators().accept(memberVisitor); + if (memberVisitor.found()) { + return new SuperExpression(expression.getLineNumber(), expression.getType()); + } } } } @@ -1931,13 +1921,17 @@ private Expression getFieldInstanceReference(Expression expression, ObjectType o * @return expression, 'this' or 'super' */ private Expression getMethodInstanceReference(Expression expression, ObjectType ot, String name, String descriptor) { - if ((bodyDeclaration.getMethodDeclarations() != null) && (expression.getClass() == ThisExpression.class) && !ot.equals(expression.getType())) { - memberVisitor.init(name, descriptor); + if ((bodyDeclaration.getMethodDeclarations() != null) && (expression.getClass() == ThisExpression.class)) { + String internalName = ((ObjectType)expression.getType()).getInternalName(); - for (ClassFileConstructorOrMethodDeclaration member : bodyDeclaration.getMethodDeclarations()) { - member.accept(memberVisitor); - if (memberVisitor.isFound()) { - return new SuperExpression(expression.getLineNumber(), ((ThisExpression) expression).getObjectType()); + if (!ot.getInternalName().equals(internalName)) { + memberVisitor.init(name, descriptor); + + for (ClassFileConstructorOrMethodDeclaration member : bodyDeclaration.getMethodDeclarations()) { + member.accept(memberVisitor); + if (memberVisitor.found()) { + return new SuperExpression(expression.getLineNumber(), expression.getType()); + } } } } @@ -1958,6 +1952,39 @@ private static void checkStack(DefaultStack stack, byte[] code, int } } + private Expression checkLocalVariableReferenceExpression(Expression expression, Type type) { + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); + + localVariable.typeOnLeft(type); + + Type localVariableType = localVariable.getType(); + + if (type.isObject() && localVariableType.isObject() && !localVariableType.equals(type)) { + ObjectType objectType = (ObjectType)type; + ObjectType localVariableObjectType = (ObjectType)localVariableType; + + if (objectType.getInternalName().equals(localVariableObjectType.getInternalName())) { + searchWildcardTypeArgumentVisitor.init(); + localVariableType.accept(searchWildcardTypeArgumentVisitor); + + if (objectType.getTypeArguments() == null) { + if (searchWildcardTypeArgumentVisitor.containsWildcard() || searchWildcardTypeArgumentVisitor.containsWildcardSuperOrExtendsType()) { + ObjectType ot = new ObjectType(objectType.getInternalName(), objectType.getQualifiedName(), objectType.getName()); + return new CastExpression(expression.getLineNumber(), ot, expression); + } + } else { + if (searchWildcardTypeArgumentVisitor.containsWildcard() || searchWildcardTypeArgumentVisitor.containsWildcardSuperOrExtendsType()) { + return new CastExpression(expression.getLineNumber(), objectType, expression); + } + } + } + } + } + + return expression; + } + public static boolean isAssertCondition(String internalTypeName, BasicBlock basicBlock) { ControlFlowGraph cfg = basicBlock.getControlFlowGraph(); int offset = basicBlock.getFromOffset(); @@ -2452,7 +2479,7 @@ public void init(String name, String descriptor) { this.found = false; } - public boolean isFound() { + public boolean found() { return found; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 87171cc6..fd6e5530 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -450,8 +450,12 @@ public void visit(NewExpression expression) { Iterator outerParameterNameIterator = outerParameterNames.iterator(); while (parameterIterator.hasNext()) { - Expression param = parameterIterator.next(); String outerParameterName = outerParameterNameIterator.next(); + Expression param = parameterIterator.next(); + + if (param.getClass() == CastExpression.class) { + param = ((CastExpression)param).getExpression(); + } if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { String localVariableName = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable().getName(); @@ -461,16 +465,24 @@ public void visit(NewExpression expression) { lastParameters.clear(); } - } else if (parameters.getClass() == ClassFileLocalVariableReferenceExpression.class) { - if (outerParameterNames != null) { - expression.setParameters(null); - String localVariableName = ((ClassFileLocalVariableReferenceExpression) parameters).getLocalVariable().getName(); - String outerParameterName = outerParameterNames.get(0); - finalLocalVariableNameMap.put(localVariableName, outerParameterName.substring(4)); + } else { + Expression param = parameters.getFirst(); + + if (param.getClass() == CastExpression.class) { + param = ((CastExpression)param).getExpression(); } - } else if (parameters.getClass() == ThisExpression.class) { - if (cfbd.getOuterType() != null) { - expression.setParameters(null); + + if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { + if (outerParameterNames != null) { + expression.setParameters(null); + String localVariableName = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable().getName(); + String outerParameterName = outerParameterNames.get(0); + finalLocalVariableNameMap.put(localVariableName, outerParameterName.substring(4)); + } + } else if (param.getClass() == ThisExpression.class) { + if (cfbd.getOuterType() != null) { + expression.setParameters(null); + } } } } diff --git a/src/test/java/org/jd/core/v1/loader/ZipLoader.java b/src/test/java/org/jd/core/v1/loader/ZipLoader.java index f43235fc..3b037cff 100644 --- a/src/test/java/org/jd/core/v1/loader/ZipLoader.java +++ b/src/test/java/org/jd/core/v1/loader/ZipLoader.java @@ -48,6 +48,8 @@ public ZipLoader(InputStream is) throws LoaderException { } } + public HashMap getMap() { return map; } + @Override public byte[] load(String internalName) throws LoaderException { return map.get(internalName + ".class"); diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java index 539bf684..b5022740 100644 --- a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java +++ b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java @@ -29,6 +29,12 @@ public PlainTextPrinter(boolean escapeUnicodeCharacters) { this.escapeUnicodeCharacters = escapeUnicodeCharacters; } + public void init() { + sb.setLength(0); + realLineNumber = 0; + indentationCount = 0; + } + public String toString() { return sb.toString(); } // --- Printer --- // From 0b16617d5e5c8b71d9fdc6b3617ff9524a09f468 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 12:44:17 +0200 Subject: [PATCH 062/211] Improve RemoveBinaryOpReturnStatementsVisitor --- ...RemoveBinaryOpReturnStatementsVisitor.java | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java index d4a6c898..719c2b1d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveBinaryOpReturnStatementsVisitor.java @@ -38,30 +38,33 @@ public void visit(Statements statements) { if (res.getExpression().getClass() == ClassFileLocalVariableReferenceExpression.class) { ClassFileLocalVariableReferenceExpression lvr1 = (ClassFileLocalVariableReferenceExpression)res.getExpression(); - Statement statement = (Statement)statements.get(statements.size()-2); - if (statement.getClass() == ExpressionStatement.class) { - ExpressionStatement es = (ExpressionStatement)statement; + if (lvr1.getName() == null) { + Statement statement = (Statement)statements.get(statements.size()-2); - if (es.getExpression().getClass() == BinaryOperatorExpression.class) { - BinaryOperatorExpression boe = (BinaryOperatorExpression)es.getExpression(); - Expression leftExpression = boe.getLeftExpression(); + if (statement.getClass() == ExpressionStatement.class) { + ExpressionStatement es = (ExpressionStatement)statement; - if (leftExpression.getClass() == ClassFileLocalVariableReferenceExpression.class) { - ClassFileLocalVariableReferenceExpression lvr2 = (ClassFileLocalVariableReferenceExpression)leftExpression; + if (es.getExpression().getClass() == BinaryOperatorExpression.class) { + BinaryOperatorExpression boe = (BinaryOperatorExpression)es.getExpression(); + Expression leftExpression = boe.getLeftExpression(); - if ((lvr1.getLocalVariable() == lvr2.getLocalVariable()) && (lvr1.getLocalVariable().getReferences().size() == 2)) { - // Remove synthetic assignment statement - statements.remove(statements.size()-2); - // Replace synthetic local variable with expression - res.setExpression(boe.getRightExpression()); - // Check line number - int expressionLineNumber = boe.getRightExpression().getLineNumber(); - if (res.getLineNumber() > expressionLineNumber) { - res.setLineNumber(expressionLineNumber); + if (leftExpression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + ClassFileLocalVariableReferenceExpression lvr2 = (ClassFileLocalVariableReferenceExpression) leftExpression; + + if ((lvr1.getLocalVariable() == lvr2.getLocalVariable()) && (lvr1.getLocalVariable().getReferences().size() == 2)) { + // Remove synthetic assignment statement + statements.remove(statements.size() - 2); + // Replace synthetic local variable with expression + res.setExpression(boe.getRightExpression()); + // Check line number + int expressionLineNumber = boe.getRightExpression().getLineNumber(); + if (res.getLineNumber() > expressionLineNumber) { + res.setLineNumber(expressionLineNumber); + } + // Remove synthetic local variable + localVariableMaker.removeLocalVariable(lvr1.getLocalVariable()); } - // Remove synthetic local variable - localVariableMaker.removeLocalVariable(lvr1.getLocalVariable()); } } } From 41771d6b7ef520e8bb187e4440a37c48a1bdd266 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 12:48:04 +0200 Subject: [PATCH 063/211] Update JarFileToJavaSourceTest --- src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 75374789..7fe47388 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -95,9 +95,9 @@ protected void test(InputStream inputStream) throws Exception { // Recompile source String source = printer.toString(); - if (!CompilerUtil.compile("1.8", new JavaSourceFileObject(internalTypeName, source))) { - recompilationFailedCounter++; - } + // TODO if (!CompilerUtil.compile("1.8", new JavaSourceFileObject(internalTypeName, source))) { + // TODO recompilationFailedCounter++; + // TODO } } } From ca1dec9fc5770ab1b4d961bc8673bf73d60d5f07 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 22:56:46 +0200 Subject: [PATCH 064/211] Improve the generation of generic local variables --- .../javasyntax/type/ArrayTypeArguments.java | 27 ++++++++++++++++++- .../javasyntax/type/BaseTypeArgument.java | 3 ++- .../javasyntax/type/DiamondTypeArgument.java | 7 ++++- .../v1/model/javasyntax/type/GenericType.java | 15 ++++++++++- .../v1/model/javasyntax/type/ObjectType.java | 21 +++++++++++++++ .../model/javasyntax/type/PrimitiveType.java | 5 ++++ .../type/WildcardExtendsTypeArgument.java | 13 ++++++++- .../type/WildcardSuperTypeArgument.java | 13 ++++++++- .../javasyntax/type/WildcardTypeArgument.java | 5 ++++ .../localvariable/GenericLocalVariable.java | 17 +++++++++++- .../localvariable/ObjectLocalVariable.java | 20 ++++++++++++-- .../util/LocalVariableMaker.java | 18 ++++++++++--- 12 files changed, 151 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java index 50a21c32..df1784a5 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -9,6 +9,7 @@ import org.jd.core.v1.util.DefaultList; +import java.util.Iterator; import java.util.List; public class ArrayTypeArguments extends DefaultList implements BaseTypeArgument { @@ -22,4 +23,28 @@ public ArrayTypeArguments(List list) { public void accept(TypeVisitor visitor) { visitor.visit(this); } + + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + if (typeArgument.getClass() != ArrayTypeArguments.class) { + return false; + } + + ArrayTypeArguments ata = (ArrayTypeArguments)typeArgument; + + if (size() != ata.size()) { + return false; + } + + Iterator iterator1 = iterator(); + Iterator iterator2 = ata.iterator(); + + while (iterator1.hasNext()) { + if (!iterator1.next().isTypeArgumentAssignableFrom(iterator2.next())) { + return false; + } + } + + return true; + } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java index 66b83784..24d9330f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,4 +8,5 @@ package org.jd.core.v1.model.javasyntax.type; public interface BaseTypeArgument extends TypeVisitable { + boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java index 44706f7c..551759c2 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -16,4 +16,9 @@ protected DiamondTypeArgument() {} public void accept(TypeVisitor visitor) { visitor.visit(this); } + + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + return true; + } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java index 1361e0c4..964ca3d6 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java @@ -65,6 +65,11 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + return equals(typeArgument); + } + @Override public boolean isGeneric() { return true; @@ -72,6 +77,14 @@ public boolean isGeneric() { @Override public String toString() { - return "GenericType{" + name + "}"; + StringBuilder sb = new StringBuilder("GenericType{"); + + sb.append(name); + + if (dimension > 0) { + sb.append(", dimension=").append(dimension); + } + + return sb.append('}').toString(); } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index 25ee49b6..96208935 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -191,6 +191,27 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + if (typeArgument.getClass() != ObjectType.class) { + return false; + } + + ObjectType ot = (ObjectType)typeArgument; + + if ((dimension != ot.getDimension()) || !internalName.equals(ot.getInternalName())) { + return false; + } + + if (ot.getTypeArguments() == null) { + return (typeArgument == null); + } else if (typeArgument == null) { + return false; + } else { + return typeArguments.isTypeArgumentAssignableFrom(ot.getTypeArguments()); + } + } + @Override public boolean isObject() { return true; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java index edaa6829..8652177b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java @@ -153,6 +153,11 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + return equals(typeArgument); + } + @Override public boolean isPrimitive() { return true; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java index 469dab87..4b03a5b7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -23,6 +23,17 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + if (typeArgument.getClass() == WildcardExtendsTypeArgument.class) { + return type.isTypeArgumentAssignableFrom(((WildcardExtendsTypeArgument)typeArgument).getType()); + } else if (typeArgument instanceof Type) { + return type.isTypeArgumentAssignableFrom(typeArgument); + } + + return false; + } + @Override public String toString() { return "WildcardExtendsTypeArgument{? extends " + type + "}"; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java index 4ec1002c..1706c08d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -23,6 +23,17 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + if (typeArgument.getClass() == WildcardSuperTypeArgument.class) { + return type.isTypeArgumentAssignableFrom(((WildcardSuperTypeArgument)typeArgument).getType()); + } else if (typeArgument instanceof Type) { + return type.isTypeArgumentAssignableFrom(typeArgument); + } + + return false; + } + @Override public String toString() { return "WildcardSuperTypeArgument{? super " + type + "}"; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java index 45292b8f..d98ba96e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java @@ -18,4 +18,9 @@ public void accept(TypeVisitor visitor) { public String toString() { return "Wildcard{?}"; } + + @Override + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + return true; + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java index db12067e..84a98e7c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java @@ -40,7 +40,22 @@ public void accept(LocalVariableVisitor visitor) { @Override public String toString() { - return "GenericLocalVariable{" + type + ", index=" + index + "}"; + StringBuilder sb = new StringBuilder(); + + sb.append("GenericLocalVariable{"); + sb.append(type.getName()); + + if (type.getDimension() > 0) { + sb.append(new String(new char[type.getDimension()]).replaceAll("\0", "[]")); + } + + sb.append(' ').append(name).append(", index=").append(index); + + if (next != null) { + sb.append(", next=").append(next); + } + + return sb.append("}").toString(); } @Override public boolean isAssignableFrom(Type otherType) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 3fbec761..3ddb7947 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -82,8 +82,24 @@ public boolean isAssignableFrom(Type type) { if (!type.isPrimitive()) { if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_OBJECT) || this.type.equals(type)) { return true; - } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0) && this.type.isObject() && type.isObject()) { - return objectTypeMaker.isAssignable((ObjectType) this.type, (ObjectType) type); + } else if ((this.type.getDimension() == type.getDimension()) && this.type.isObject()) { + ObjectType ot1 = (ObjectType) this.type; + + if (type.isObject()) { + ObjectType ot2 = (ObjectType) type; + + if (ot1.getInternalName().equals(ot2.getInternalName()) && (ot1.getTypeArguments() != null) && (ot2.getTypeArguments() != null)) { + return ot1.getTypeArguments().isTypeArgumentAssignableFrom(ot2.getTypeArguments()); + } + + if (type.getDimension() == 0) { + if ((ot1.getTypeArguments() == null) ? (ot2.getTypeArguments() == null) : ot1.getTypeArguments().equals(ot2.getTypeArguments())) { + return objectTypeMaker.isAssignable(ot1, ot2); + } + } + } else if (ot1.getInternalName().equals(TYPE_OBJECT.getInternalName())) { + return true; + } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 9656d436..1d3f1b42 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -335,6 +335,14 @@ protected AbstractLocalVariable searchLocalVariable(int index, int offset) { return lv; } + protected boolean isAssignableFrom(AbstractLocalVariable lv, Type valueType) { + if (lv.getType().isObject() && valueType.isObject() && (lv.getType().getDimension() == valueType.getDimension())) { + return objectTypeMaker.isAssignable((ObjectType)lv.getType(), (ObjectType)valueType); + } + + return false; + } + public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, Type valueType) { AbstractLocalVariable lv = searchLocalVariable(index, offset); @@ -343,10 +351,10 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, createLocalVariableVisitor.init(index, offset); valueType.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); - } else if (lv.isAssignableFrom(valueType)) { + } else if (lv.isAssignableFrom(valueType) || isAssignableFrom(lv, valueType)) { // Reduce type lv.typeOnRight(valueType); - } else { + } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueType)) { // Not assignable -> Create a new local variable createLocalVariableVisitor.init(index, offset); valueType.accept(createLocalVariableVisitor); @@ -392,14 +400,16 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, createLocalVariableVisitor.init(index, offset); valueLocalVariable.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); - } else if (!lv.isAssignableFrom(valueLocalVariable)) { + } else if (lv.isAssignableFrom(valueLocalVariable) || isAssignableFrom(lv, valueLocalVariable.getType())) { + // Reduce type + lv.variableOnRight(valueLocalVariable); + } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueLocalVariable.getType())) { // Not assignable -> Create a new local variable createLocalVariableVisitor.init(index, offset); valueLocalVariable.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); } - lv.variableOnRight(valueLocalVariable); lv.setToOffset(offset); store(lv); From 068c2b93fbdd7c443147909fca07fdeafb602616 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 15 Aug 2019 22:57:31 +0200 Subject: [PATCH 065/211] Update comments --- .../converter/classfiletojavasyntax/util/StatementMaker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 13ef828f..16aaad18 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -94,7 +94,7 @@ public Statements make(ControlFlowGraph cfg) { statements.accept(MERGE_TRY_WITH_RESOURCES_STATEMENT_VISITOR); } - // Replace pattern "local_var_2 = ...; return local_var_2;" with "return ...;" + // Replace pattern "synthetic_local_var = ...; return synthetic_local_var;" with "return ...;" statements.accept(removeBinaryOpReturnStatementsVisitor); // Remove last 'return' statement From c7871965682c5b5cc91770995af35b08ddcf35c1 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 16 Aug 2019 11:44:55 +0200 Subject: [PATCH 066/211] Improve the generation of generic local variables --- .../localvariable/GenericLocalVariable.java | 1 - .../localvariable/ObjectLocalVariable.java | 55 +++++++++++-------- .../util/ByteCodeParser.java | 2 +- .../util/LocalVariableMaker.java | 15 +++-- .../util/LoopStatementMaker.java | 3 + 5 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java index 84a98e7c..8356e1d1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java @@ -61,7 +61,6 @@ public String toString() { @Override public boolean isAssignableFrom(Type otherType) { return type.equals(otherType); } - @Override public void typeOnRight(Type type) {} @Override public void typeOnLeft(Type type) {} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 3ddb7947..e8062164 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -83,21 +83,21 @@ public boolean isAssignableFrom(Type type) { if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_OBJECT) || this.type.equals(type)) { return true; } else if ((this.type.getDimension() == type.getDimension()) && this.type.isObject()) { - ObjectType ot1 = (ObjectType) this.type; + ObjectType thisObjectType = (ObjectType) this.type; if (type.isObject()) { - ObjectType ot2 = (ObjectType) type; + ObjectType otherObjectType = (ObjectType) type; - if (ot1.getInternalName().equals(ot2.getInternalName()) && (ot1.getTypeArguments() != null) && (ot2.getTypeArguments() != null)) { - return ot1.getTypeArguments().isTypeArgumentAssignableFrom(ot2.getTypeArguments()); + if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName()) && (thisObjectType.getTypeArguments() != null) && (otherObjectType.getTypeArguments() != null)) { + return thisObjectType.getTypeArguments().isTypeArgumentAssignableFrom(otherObjectType.getTypeArguments()); } if (type.getDimension() == 0) { - if ((ot1.getTypeArguments() == null) ? (ot2.getTypeArguments() == null) : ot1.getTypeArguments().equals(ot2.getTypeArguments())) { - return objectTypeMaker.isAssignable(ot1, ot2); + if ((thisObjectType.getTypeArguments() == null) ? (otherObjectType.getTypeArguments() == null) : thisObjectType.getTypeArguments().equals(otherObjectType.getTypeArguments())) { + return objectTypeMaker.isAssignable(thisObjectType, otherObjectType); } } - } else if (ot1.getInternalName().equals(TYPE_OBJECT.getInternalName())) { + } else if (thisObjectType.getInternalName().equals(TYPE_OBJECT.getInternalName())) { return true; } } @@ -115,8 +115,9 @@ public void typeOnRight(Type type) { assert !this.type.isPrimitive() && !type.isPrimitive() : "ObjectLocalVariable.typeOnRight(type) : unexpected type"; if (this.type.isObject()) { + ObjectType thisObjectType = (ObjectType) this.type; + if (type.isObject()) { - ObjectType thisObjectType = (ObjectType) this.type; ObjectType otherObjectType = (ObjectType) type; if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { @@ -133,7 +134,7 @@ public void typeOnRight(Type type) { fireChangeEvent(); } } - } else if (type.isGeneric() && (this.type == TYPE_OBJECT)) { + } else if (type.isGeneric() && thisObjectType.getInternalName().equals(TYPE_OBJECT.getInternalName())) { this.type = type; fireChangeEvent(); } @@ -150,23 +151,29 @@ public void typeOnLeft(Type type) { } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { assert !this.type.isPrimitive() && !type.isPrimitive() : "unexpected type in ObjectLocalVariable.typeOnLeft(type)"; - if (this.type.isObject() && type.isObject()) { - ObjectType thisObjectType = (ObjectType)this.type; - ObjectType otherObjectType = (ObjectType)type; + if (this.type.isObject()) { + ObjectType thisObjectType = (ObjectType) this.type; - if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { - if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { - // Keep type, update type arguments - this.type = otherObjectType; - fireChangeEvent(); - } - } else if (objectTypeMaker.isAssignable(otherObjectType, thisObjectType)) { - // Assignable types - if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { - // Keep type, update type arguments - this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); - fireChangeEvent(); + if (type.isObject()) { + ObjectType otherObjectType = (ObjectType) type; + + if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = otherObjectType; + fireChangeEvent(); + } + } else if (objectTypeMaker.isAssignable(otherObjectType, thisObjectType)) { + // Assignable types + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); + fireChangeEvent(); + } } + } else if (type.isGeneric() && thisObjectType.getInternalName().equals(TYPE_OBJECT.getInternalName())) { + this.type = type; + fireChangeEvent(); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 2477546f..8bfe8037 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1419,7 +1419,7 @@ private void parseASTORE(Statements statements, DefaultStack Create a new local variable @@ -401,8 +406,7 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, valueLocalVariable.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); } else if (lv.isAssignableFrom(valueLocalVariable) || isAssignableFrom(lv, valueLocalVariable.getType())) { - // Reduce type - lv.variableOnRight(valueLocalVariable); + // Assignable } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueLocalVariable.getType())) { // Not assignable -> Create a new local variable createLocalVariableVisitor.init(index, offset); @@ -410,6 +414,7 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, lv = createLocalVariableVisitor.getLocalVariable(); } + lv.variableOnRight(valueLocalVariable); lv.setToOffset(offset); store(lv); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index 09fa957e..6feb71fe 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -441,6 +441,7 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake return null; } + Type arrayType = boe.getRightExpression().getType(); Expression array = boe.getRightExpression(); // i$ = 0; @@ -501,6 +502,8 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake subStatements.removeLast(); item.setDeclared(true); + Type itemType = arrayType.createType(arrayType.getDimension()-1); + item.typeOnRight(itemType); localVariableMaker.removeLocalVariable(syntheticArray); localVariableMaker.removeLocalVariable(syntheticIndex); From ecf9843ee22bfe58363599432bb6e19ebe62c9dc Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 17 Aug 2019 11:53:50 +0200 Subject: [PATCH 067/211] Fix bug on parameters in method invocations --- .../javasyntax/expression/NewExpression.java | 7 +-- .../javasyntax/type/WildcardTypeArgument.java | 3 + ...ssFileConstructorInvocationExpression.java | 27 ++++++++ .../ClassFileMethodInvocationExpression.java | 27 ++++++++ .../expression/ClassFileNewExpression.java | 37 +++++++++++ ...eSuperConstructorInvocationExpression.java | 27 ++++++++ .../UpdateJavaSyntaxTreeProcessor.java | 12 ++-- .../util/ByteCodeParser.java | 63 +++++++++---------- .../util/LoopStatementMaker.java | 7 ++- .../util/SignatureParser.java | 33 ++++------ .../util/StatementMaker.java | 12 ++-- .../util/StringConcatenationUtil.java | 12 ++-- .../util/SwitchStatementMaker.java | 16 ++--- .../util/TryWithResourcesStatementMaker.java | 10 +-- .../visitor/InitInnerClassVisitor.java | 63 ++++++++++++------- .../visitor/InitInstanceFieldVisitor.java | 13 ++-- .../RemoveDefaultConstructorVisitor.java | 13 ++-- .../visitor/UpdateBridgeMethodVisitor.java | 9 +-- .../UpdateIntegerConstantTypeVisitor.java | 16 ++--- .../UpdateJavaSyntaxTreeStep1Visitor.java | 38 +++++++++++ ... => UpdateJavaSyntaxTreeStep2Visitor.java} | 50 ++++++--------- src/test/java/org/jd/core/v1/TypeTest.java | 2 +- 22 files changed, 325 insertions(+), 172 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java rename src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/{UpdateJavaSyntaxTreeVisitor.java => UpdateJavaSyntaxTreeStep2Visitor.java} (79%) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java index 5ae16c2d..395e39bf 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -73,11 +73,6 @@ public void setParameters(BaseExpression parameters) { this.parameters = parameters; } - public void setDescriptorAndParameters(String descriptor, BaseExpression parameters) { - this.descriptor = descriptor; - this.parameters = parameters; - } - public BodyDeclaration getBodyDeclaration() { return bodyDeclaration; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java index d98ba96e..a817bd2c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java @@ -8,6 +8,9 @@ package org.jd.core.v1.model.javasyntax.type; public class WildcardTypeArgument implements TypeArgument { + public static final WildcardTypeArgument WILDCARD_TYPE_ARGUMENT = new WildcardTypeArgument(); + + private WildcardTypeArgument() {} @Override public void accept(TypeVisitor visitor) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java new file mode 100644 index 00000000..2b0c8c0b --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; +import org.jd.core.v1.model.javasyntax.expression.ConstructorInvocationExpression; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.util.DefaultList; + +public class ClassFileConstructorInvocationExpression extends ConstructorInvocationExpression { + protected DefaultList parameterTypes; + + public ClassFileConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + super(lineNumber, type, descriptor, parameters); + this.parameterTypes = parameterTypes; + } + + public DefaultList getParameterTypes() { + return parameterTypes; + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java new file mode 100644 index 00000000..688f4ad1 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; +import org.jd.core.v1.model.javasyntax.expression.Expression; +import org.jd.core.v1.model.javasyntax.expression.MethodInvocationExpression; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.util.DefaultList; + +public class ClassFileMethodInvocationExpression extends MethodInvocationExpression { + protected DefaultList parameterTypes; + + public ClassFileMethodInvocationExpression(int lineNumber, Type type, Expression expression, String internalTypeName, String name, String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + super(lineNumber, type, expression, internalTypeName, name, descriptor, parameters); + this.parameterTypes = parameterTypes; + } + + public DefaultList getParameterTypes() { + return parameterTypes; + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java new file mode 100644 index 00000000..8044afb5 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; +import org.jd.core.v1.model.javasyntax.expression.NewExpression; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.util.DefaultList; + +public class ClassFileNewExpression extends NewExpression { + protected DefaultList parameterTypes; + + public ClassFileNewExpression(int lineNumber, ObjectType type) { + super(lineNumber, type); + } + + public ClassFileNewExpression(int lineNumber, ObjectType type, BodyDeclaration bodyDeclaration) { + super(lineNumber, type, bodyDeclaration); + } + + public DefaultList getParameterTypes() { + return parameterTypes; + } + + public void set(String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + this.descriptor = descriptor; + this.parameterTypes = parameterTypes; + this.parameters = parameters; + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java new file mode 100644 index 00000000..a1424877 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; +import org.jd.core.v1.model.javasyntax.expression.SuperConstructorInvocationExpression; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.util.DefaultList; + +public class ClassFileSuperConstructorInvocationExpression extends SuperConstructorInvocationExpression { + protected DefaultList parameterTypes; + + public ClassFileSuperConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + super(lineNumber, type, descriptor, parameters); + this.parameterTypes = parameterTypes; + } + + public DefaultList getParameterTypes() { + return parameterTypes; + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java index 08a03701..1a8d617c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -12,7 +12,8 @@ import org.jd.core.v1.model.processor.Processor; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; -import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.UpdateJavaSyntaxTreeVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.UpdateJavaSyntaxTreeStep1Visitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.UpdateJavaSyntaxTreeStep2Visitor; /** * Create statements, init fields, merge declarations.

@@ -28,7 +29,10 @@ public void process(Message message) throws Exception { SignatureParser parser = message.getHeader("signatureParser"); CompilationUnit compilationUnit = message.getBody(); - UpdateJavaSyntaxTreeVisitor updateJavaSyntaxTreeVisitor = new UpdateJavaSyntaxTreeVisitor(maker, parser); - updateJavaSyntaxTreeVisitor.visit(compilationUnit); + UpdateJavaSyntaxTreeStep1Visitor updateJavaSyntaxTreeStep1Visitor = new UpdateJavaSyntaxTreeStep1Visitor(maker, parser); + updateJavaSyntaxTreeStep1Visitor.visit(compilationUnit); + + UpdateJavaSyntaxTreeStep2Visitor updateJavaSyntaxTreeStep2Visitor = new UpdateJavaSyntaxTreeStep2Visitor(); + updateJavaSyntaxTreeStep2Visitor.visit(compilationUnit); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 8bfe8037..1417421a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -25,8 +25,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileCmpExpression; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileMonitorEnterStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileMonitorExitStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; @@ -729,11 +728,12 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - BaseExpression parameters = getParameters(statements, stack, descriptor); + DefaultList parameterTypes = signatureParser.parseParameterTypes(descriptor); + BaseExpression parameters = getParameters(statements, stack, parameterTypes); Type returnedType = signatureParser.parseReturnedType(descriptor); if (opcode == 184) { // INVOKESTATIC - expression1 = new MethodInvocationExpression(lineNumber, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameters); + expression1 = new ClassFileMethodInvocationExpression(lineNumber, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameterTypes, parameters); if (TYPE_VOID.equals(returnedType)) { statements.add(new ExpressionStatement(expression1)); } else { @@ -751,15 +751,15 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau if ((opcode == 183) && // INVOKESPECIAL "".equals(name)) { - if (expression1.getClass() == NewExpression.class) { - ((NewExpression)expression1).setDescriptorAndParameters(descriptor, parameters); + if (expression1.getClass() == ClassFileNewExpression.class) { + ((ClassFileNewExpression)expression1).set(descriptor, parameterTypes, parameters); } else if (ot.getInternalName().equals(((ObjectType)expression1.getType()).getInternalName())) { - statements.add(new ExpressionStatement(new ConstructorInvocationExpression(lineNumber, ot, descriptor, parameters))); + statements.add(new ExpressionStatement(new ClassFileConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); } else { - statements.add(new ExpressionStatement(new SuperConstructorInvocationExpression(lineNumber, ot, descriptor, parameters))); + statements.add(new ExpressionStatement(new ClassFileSuperConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); } } else { - statements.add(new ExpressionStatement(new MethodInvocationExpression(lineNumber, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameters))); + statements.add(new ExpressionStatement(new ClassFileMethodInvocationExpression(lineNumber, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters))); } } else { if ((opcode == 182) && // INVOKEVIRTUAL @@ -770,7 +770,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; } } - stack.push(new MethodInvocationExpression(lineNumber, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameters)); + stack.push(new ClassFileMethodInvocationExpression(lineNumber, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters)); } } break; @@ -911,10 +911,8 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } @SuppressWarnings("unchecked") - private BaseExpression getParameters(Statements statements, DefaultStack stack, String descriptor) { - List types = signatureParser.parseParameterTypes(descriptor); - - switch (types.size()) { + private BaseExpression getParameters(Statements statements, DefaultStack stack, DefaultList parameterTypes) { + switch (parameterTypes.size()) { case 0: return null; case 1: @@ -922,17 +920,17 @@ private BaseExpression getParameters(Statements statements, DefaultStack=0; --i) { parameter = stack.pop(); if (parameter.getClass() == NewArray.class) { parameter = NewArrayMaker.make(statements, (NewArray)parameter); } - parameters.add(checkLocalVariableReferenceExpression(checkIfLastStatementIsAMultiAssignment(statements, parameter), types.get(i))); + parameters.add(checkLocalVariableReferenceExpression(checkIfLastStatementIsAMultiAssignment(statements, parameter), parameterTypes.get(i))); } Collections.reverse(parameters); @@ -1262,7 +1260,7 @@ private void parseInvokeDynamic(Statements statements, DefaultStack statements, DefaultStack indyParameterTypes = signatureParser.parseParameterTypes(indyDescriptor); + BaseExpression indyParameters = getParameters(statements, stack, indyParameterTypes); + Type indyReturnType = signatureParser.parseReturnedType(indyDescriptor); BootstrapMethod bootstrapMethod = attributeBootstrapMethods.getBootstrapMethods()[constantMemberRef.getClassIndex()]; int[] bootstrapArguments = bootstrapMethod.getBootstrapArguments(); @@ -1312,7 +1311,7 @@ private void parseInvokeDynamic(Statements statements, DefaultStack statements, DefaultStack")) { - stack.push(new ConstructorReferenceExpression(lineNumber, indyType, ot, descriptor1)); + stack.push(new ConstructorReferenceExpression(lineNumber, indyReturnType, ot, descriptor1)); } else { - stack.push(new MethodReferenceExpression(lineNumber, indyType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name1, descriptor1)); + stack.push(new MethodReferenceExpression(lineNumber, indyReturnType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name1, descriptor1)); } return; } // Create method reference - stack.push(new MethodReferenceExpression(lineNumber, indyType, (Expression)indyParameters, typeName, name1, descriptor1)); + stack.push(new MethodReferenceExpression(lineNumber, indyReturnType, (Expression)indyParameters, typeName, name1, descriptor1)); } private static List prepareLambdaParameters(BaseFormalParameter formalParameters, int parameterCount) { @@ -1732,21 +1731,21 @@ private Expression newNewExpression(int lineNumber, String internalName) { ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); if (memberDeclaration == null) { - return new NewExpression(lineNumber, ObjectType.TYPE_OBJECT); + return new ClassFileNewExpression(lineNumber, ObjectType.TYPE_OBJECT); } else if (memberDeclaration.getClass() == ClassFileClassDeclaration.class) { ClassFileClassDeclaration declaration = (ClassFileClassDeclaration) memberDeclaration; if (declaration.getInterfaces() != null) { - return new NewExpression(lineNumber, (ObjectType) declaration.getInterfaces(), declaration.getBodyDeclaration()); + return new ClassFileNewExpression(lineNumber, (ObjectType) declaration.getInterfaces(), declaration.getBodyDeclaration()); } else if (declaration.getSuperType() != null) { - return new NewExpression(lineNumber, (ObjectType) declaration.getSuperType(), declaration.getBodyDeclaration()); + return new ClassFileNewExpression(lineNumber, (ObjectType) declaration.getSuperType(), declaration.getBodyDeclaration()); } else { - return new NewExpression(lineNumber, ObjectType.TYPE_OBJECT, declaration.getBodyDeclaration()); + return new ClassFileNewExpression(lineNumber, ObjectType.TYPE_OBJECT, declaration.getBodyDeclaration()); } } } - return new NewExpression(lineNumber, objectType); + return new ClassFileNewExpression(lineNumber, objectType); } /* @@ -1970,8 +1969,8 @@ private Expression checkLocalVariableReferenceExpression(Expression expression, if (objectType.getTypeArguments() == null) { if (searchWildcardTypeArgumentVisitor.containsWildcard() || searchWildcardTypeArgumentVisitor.containsWildcardSuperOrExtendsType()) { - ObjectType ot = new ObjectType(objectType.getInternalName(), objectType.getQualifiedName(), objectType.getName()); - return new CastExpression(expression.getLineNumber(), ot, expression); + ObjectType ot = objectType.createType(null); + return new CastExpression(expression.getLineNumber(), objectType.createType(null), expression); } } else { if (searchWildcardTypeArgumentVisitor.containsWildcard() || searchWildcardTypeArgumentVisitor.containsWildcardSuperOrExtendsType()) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index 6feb71fe..c9e202f4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -13,6 +13,7 @@ import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileBreakContinueStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForEachStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; @@ -522,7 +523,7 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker } // i$.hasNext(); - if (condition.getClass() != MethodInvocationExpression.class) { + if (condition.getClass() != ClassFileMethodInvocationExpression.class) { return null; } @@ -553,7 +554,7 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker BinaryOperatorExpression boe = (BinaryOperatorExpression)es.getExpression(); - if ((boe == null) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getRightExpression().getClass() != MethodInvocationExpression.class) || (boe.getLineNumber() != condition.getLineNumber())) { + if ((boe == null) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getRightExpression().getClass() != ClassFileMethodInvocationExpression.class) || (boe.getLineNumber() != condition.getLineNumber())) { return null; } @@ -592,7 +593,7 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker if (boe.getRightExpression().getClass() == CastExpression.class) { expression = ((CastExpression)expression).getExpression(); } - if (expression.getClass() != MethodInvocationExpression.class) { + if (expression.getClass() != ClassFileMethodInvocationExpression.class) { return null; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java index c1b5afba..e72b14d0 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java @@ -15,9 +15,7 @@ import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.util.DefaultList; -import java.util.Collections; import java.util.HashMap; -import java.util.List; /* * https://jcp.org/aboutJava/communityprocess/maintenance/jsr924/JVMS-SE5.0-Ch4-ClassFile.pdf @@ -27,8 +25,6 @@ * http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html */ public class SignatureParser { - protected static final WildcardTypeArgument WILDCARD_TYPE_ARGUMENT = new WildcardTypeArgument(); - protected HashMap methodTypesCache = new HashMap<>(1024); protected HashMap typeCache = new HashMap<>(1024); protected ObjectTypeMaker objectTypeMaker; @@ -174,9 +170,9 @@ public Type parseTypeSignature(String signature) { return type; } - public List parseParameterTypes(String signature) { + public DefaultList parseParameterTypes(String signature) { MethodTypes methodTypes = parseMethodSignature(signature, null); - return (methodTypes==null) ? Collections.emptyList() : methodTypes.parameters; + return (methodTypes==null) ? DefaultList.emptyList() : methodTypes.parameters; } public Type parseReturnedType(String signature) { @@ -235,24 +231,19 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { Type firstParameter = parseReferenceTypeSignature(reader); if (firstParameter == null) { - methodTypes.parameters = Collections.emptyList(); + methodTypes.parameters = DefaultList.emptyList(); } else { Type nextParameter = parseReferenceTypeSignature(reader); + DefaultList list = new DefaultList<>(); - if (nextParameter == null) { - methodTypes.parameters = Collections.singletonList(firstParameter); - } else { - DefaultList list = new DefaultList<>(); - - list.add(firstParameter); + list.add(firstParameter); - do { - list.add(nextParameter); - nextParameter = parseReferenceTypeSignature(reader); - } while (nextParameter != null); - - methodTypes.parameters = list; + while (nextParameter != null) { + list.add(nextParameter); + nextParameter = parseReferenceTypeSignature(reader); } + + methodTypes.parameters = list; } if (reader.read() != ')') @@ -681,7 +672,7 @@ protected TypeArgument parseTypeArgument(SignatureReader reader) { case '-': return new WildcardSuperTypeArgument(parseReferenceTypeSignature(reader)); case '*': - return WILDCARD_TYPE_ARGUMENT; + return WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; default: // Unread 'c' reader.index--; @@ -793,7 +784,7 @@ public static class TypeTypes { public static class MethodTypes { public BaseTypeParameter typeParameters; - public List parameters; + public DefaultList parameters; public Type returned; public BaseType exceptions; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 16aaad18..67187503 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -24,6 +24,8 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFieldDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileNewExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileBreakContinueStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileMonitorEnterStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileMonitorExitStatement; @@ -43,7 +45,6 @@ public class StatementMaker { protected static final MergeTryWithResourcesStatementVisitor MERGE_TRY_WITH_RESOURCES_STATEMENT_VISITOR = new MergeTryWithResourcesStatementVisitor(); protected ObjectTypeMaker objectTypeMaker; - protected SignatureParser signatureParser; protected LocalVariableMaker localVariableMaker; protected ByteCodeParser byteCodeParser; protected int majorVersion; @@ -62,7 +63,6 @@ public StatementMaker( ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, LocalVariableMaker localVariableMaker, ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration, Type returnedType) { this.objectTypeMaker = objectTypeMaker; - this.signatureParser = signatureParser; this.localVariableMaker = localVariableMaker; this.majorVersion = classFile.getMajorVersion(); this.internalTypeName = classFile.getInternalTypeName(); @@ -70,7 +70,7 @@ public StatementMaker( this.byteCodeParser = new ByteCodeParser(objectTypeMaker, signatureParser, localVariableMaker, internalTypeName, classFile, bodyDeclaration, returnedType); this.removeFinallyStatementsVisitor = new RemoveFinallyStatementsVisitor(localVariableMaker); this.removeBinaryOpReturnStatementsVisitor = new RemoveBinaryOpReturnStatementsVisitor(localVariableMaker); - this.updateIntegerConstantTypeVisitor = new UpdateIntegerConstantTypeVisitor(signatureParser, returnedType); + this.updateIntegerConstantTypeVisitor = new UpdateIntegerConstantTypeVisitor(returnedType); } public Statements make(ControlFlowGraph cfg) { @@ -562,7 +562,7 @@ protected void parseIf(WatchDog watchdog, BasicBlock basicBlock, Statements stat if (subStatements.get(0).getClass() == ThrowStatement.class) { Expression e = ((ThrowStatement)subStatements.get(0)).getExpression(); - if (e.getClass() == NewExpression.class) { + if (e.getClass() == ClassFileNewExpression.class) { BaseExpression parameters = ((NewExpression)e).getParameters(); if ((parameters != null) && !parameters.isList()) { message = parameters.getFirst(); @@ -836,7 +836,7 @@ protected Expression parseTernaryOperator(int lineNumber, Expression condition, if (boeCond.getOperator().equals("==") && (exp1.getClass() == BinaryOperatorExpression.class) && checkFieldReference(fieldName, exp2)) { BinaryOperatorExpression boe1 = (BinaryOperatorExpression) exp1; - if ((boe1.getRightExpression().getClass() == MethodInvocationExpression.class) && checkFieldReference(fieldName, boe1.getLeftExpression())) { + if ((boe1.getRightExpression().getClass() == ClassFileMethodInvocationExpression.class) && checkFieldReference(fieldName, boe1.getLeftExpression())) { MethodInvocationExpression mie = (MethodInvocationExpression) boe1.getRightExpression(); if ((mie.getParameters().getClass() == StringConstantExpression.class) && mie.getName().equals("class$") && mie.getInternalTypeName().equals(internalTypeName)) { @@ -847,7 +847,7 @@ protected Expression parseTernaryOperator(int lineNumber, Expression condition, } else if (boeCond.getOperator().equals("!=") && (exp2.getClass() == BinaryOperatorExpression.class) && checkFieldReference(fieldName, exp1)) { BinaryOperatorExpression boe2 = (BinaryOperatorExpression) exp2; - if ((boe2.getRightExpression().getClass() == MethodInvocationExpression.class) && checkFieldReference(fieldName, boe2.getLeftExpression())) { + if ((boe2.getRightExpression().getClass() == ClassFileMethodInvocationExpression.class) && checkFieldReference(fieldName, boe2.getLeftExpression())) { MethodInvocationExpression mie = (MethodInvocationExpression) boe2.getRightExpression(); if ((mie.getParameters().getClass() == StringConstantExpression.class) && mie.getName().equals("class$") && mie.getInternalTypeName().equals(internalTypeName)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java index 5a8f477a..e796193a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -9,6 +9,8 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileNewExpression; import org.jd.core.v1.util.DefaultList; import java.util.StringTokenizer; @@ -16,14 +18,14 @@ public class StringConcatenationUtil { public static Expression create(Expression expression, int lineNumber, String typeName) { - if (expression.getClass() == MethodInvocationExpression.class) { + if (expression.getClass() == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie = (MethodInvocationExpression) expression; if ("append".equals(mie.getName()) && (mie.getParameters() != null) && !mie.getParameters().isList()) { Expression concatenatedStringExpression = mie.getParameters().getFirst(); Expression expr = mie.getExpression(); - while (expr.getClass() == MethodInvocationExpression.class) { + while (expr.getClass() == ClassFileMethodInvocationExpression.class) { mie = (MethodInvocationExpression) expr; if (("append".equals(mie.getName()) == false) || (mie.getParameters() == null) || mie.getParameters().isList()) { @@ -34,8 +36,8 @@ public static Expression create(Expression expression, int lineNumber, String ty expr = mie.getExpression(); } - if (expr.getClass() == NewExpression.class) { - NewExpression ne = (NewExpression) expr; + if (expr.getClass() == ClassFileNewExpression.class) { + ClassFileNewExpression ne = (ClassFileNewExpression) expr; String internalTypeName = ne.getType().getDescriptor(); if ("Ljava/lang/StringBuilder;".equals(internalTypeName) || "Ljava/lang/StringBuffer;".equals(internalTypeName)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java index 28cbd215..d657ca77 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -14,6 +14,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileClassDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileTryStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.util.DefaultList; @@ -21,7 +22,6 @@ import java.util.HashMap; import java.util.ListIterator; - public class SwitchStatementMaker { protected static final Integer MINUS_ONE = Integer.valueOf(-1); @@ -30,10 +30,10 @@ public static void makeSwitchString(LocalVariableMaker localVariableMaker, State int size = statements.size(); SwitchStatement previousSwitchStatement = (SwitchStatement)statements.get(size - 2); - if ((previousSwitchStatement.getCondition().getLineNumber() == switchStatement.getCondition().getLineNumber()) && (previousSwitchStatement.getCondition().getClass() == MethodInvocationExpression.class)) { + if ((previousSwitchStatement.getCondition().getLineNumber() == switchStatement.getCondition().getLineNumber()) && (previousSwitchStatement.getCondition().getClass() == ClassFileMethodInvocationExpression.class)) { Expression expression = previousSwitchStatement.getCondition(); - if (expression.getClass() == MethodInvocationExpression.class) { + if (expression.getClass() == ClassFileMethodInvocationExpression.class) { expression = ((MethodInvocationExpression)expression).getExpression(); if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { @@ -88,7 +88,7 @@ public static void makeSwitchString(LocalVariableMaker localVariableMaker, State expression = is.getCondition(); - if (expression.getClass() != MethodInvocationExpression.class) { + if (expression.getClass() != ClassFileMethodInvocationExpression.class) { break; } @@ -193,9 +193,9 @@ public static void makeSwitchEnum(ClassFileBodyDeclaration bodyDeclaration, Swit bodyDeclaration = (ClassFileBodyDeclaration)syntheticClass.getBodyDeclaration(); DefaultList statements = (DefaultList)bodyDeclaration.getMethodDeclarations().get(0).getStatements(); - updateSwitchStatement(switchStatement, statements.listIterator()); + updateSwitchStatement(switchStatement, statements.listIterator(1)); } - } else if (expressionClass == MethodInvocationExpression.class) { + } else if (expressionClass == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie = (MethodInvocationExpression)ae.getExpression(); String methodName = mie.getName(); @@ -259,7 +259,7 @@ protected static void updateSwitchStatement(SwitchStatement switchStatement, Lis expression = ((ArrayExpression)expression).getIndex(); - if (expression.getClass() != MethodInvocationExpression.class) { + if (expression.getClass() != ClassFileMethodInvocationExpression.class) { break; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java index 66d25d3a..cebadbeb 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -14,13 +14,13 @@ import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileTryStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.util.DefaultList; import java.util.List; - public class TryWithResourcesStatementMaker { public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, DefaultList catchClauses, Statements finallyStatements) { @@ -108,7 +108,7 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements outerLocalVariableNames = new DefaultList<>(); @@ -62,10 +65,6 @@ public void visit(BodyDeclaration declaration) { if ((outerType != null) || !outerLocalVariableNames.isEmpty()) { updateReferencesVisitor.visit(bodyDeclaration); } - - if (bodyDeclaration.getInnerTypeDeclarations() != null) { - updateNewExpressionVisitor.visit(bodyDeclaration); - } } @Override @@ -87,11 +86,11 @@ public void visit(ConstructorDeclaration declaration) { Expression expression = ((ExpressionStatement) statement).getExpression(); Class clazz = expression.getClass(); - if (clazz == SuperConstructorInvocationExpression.class) { + if (clazz == ClassFileSuperConstructorInvocationExpression.class) { break; } - if (clazz == ConstructorInvocationExpression.class) { + if (clazz == ClassFileConstructorInvocationExpression.class) { break; } @@ -298,7 +297,7 @@ public void visit(NewExpression expression) { } } - protected class UpdateNewExpressionVisitor extends AbstractJavaSyntaxVisitor { + public static class UpdateNewExpressionVisitor extends AbstractJavaSyntaxVisitor { protected ClassFileBodyDeclaration bodyDeclaration; protected HashMap finalLocalVariableNameMap = new HashMap<>(); protected DefaultList localClassDeclarations = new DefaultList<>(); @@ -411,7 +410,7 @@ public void visit(NewExpression expression) { if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; - cfbd = (ClassFileBodyDeclaration)cfcd.getBodyDeclaration(); + cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); if ((type.getQualifiedName() == null) && (type.getName() != null)) { // Local class @@ -423,7 +422,7 @@ public void visit(NewExpression expression) { } } else { // Anonymous class - cfbd = (ClassFileBodyDeclaration)expression.getBodyDeclaration(); + cfbd = (ClassFileBodyDeclaration) expression.getBodyDeclaration(); } if (cfbd != null) { @@ -441,8 +440,8 @@ public void visit(NewExpression expression) { list.remove(0); } - // Remove outer local variable reference if (outerParameterNames != null) { + // Remove outer local variable reference int size = list.size(); int count = outerParameterNames.size(); List lastParameters = list.subList(size - count, size); @@ -454,7 +453,7 @@ public void visit(NewExpression expression) { Expression param = parameterIterator.next(); if (param.getClass() == CastExpression.class) { - param = ((CastExpression)param).getExpression(); + param = ((CastExpression) param).getExpression(); } if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { @@ -465,23 +464,41 @@ public void visit(NewExpression expression) { lastParameters.clear(); } - } else { + } else if (cfbd.getOuterType() != null) { + // Remove outer this + expression.setParameters(null); + } else if (outerParameterNames != null) { + // Remove outer local variable reference Expression param = parameters.getFirst(); if (param.getClass() == CastExpression.class) { - param = ((CastExpression)param).getExpression(); + param = ((CastExpression) param).getExpression(); } if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { - if (outerParameterNames != null) { - expression.setParameters(null); - String localVariableName = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable().getName(); - String outerParameterName = outerParameterNames.get(0); - finalLocalVariableNameMap.put(localVariableName, outerParameterName.substring(4)); - } - } else if (param.getClass() == ThisExpression.class) { - if (cfbd.getOuterType() != null) { - expression.setParameters(null); + String localVariableName = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable().getName(); + String outerParameterName = outerParameterNames.get(0); + finalLocalVariableNameMap.put(localVariableName, outerParameterName.substring(4)); + expression.setParameters(null); + } + } + + // Is the last parameter is synthetic ? + parameters = expression.getParameters(); + + if ((parameters != null) && parameters.isList()) { + DefaultList list = parameters.getList(); + + if (!list.isEmpty()) { + Expression lastParameter = list.getLast(); + + if (lastParameter.getClass() == NullExpression.class) { + DefaultList parameterTypes = ((ClassFileNewExpression) expression).getParameterTypes(); + + if (parameterTypes.getLast().getName() == null) { + // Yes. Remove it. + list.removeLast(); + } } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java index 1c1c3fb5..75704e57 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,10 +8,6 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; import org.jd.core.v1.api.printer.Printer; -import org.jd.core.v1.model.classfile.Method; -import org.jd.core.v1.model.classfile.attribute.AttributeCode; -import org.jd.core.v1.model.classfile.attribute.AttributeLineNumberTable; -import org.jd.core.v1.model.classfile.attribute.LineNumber; import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; @@ -20,8 +16,9 @@ import org.jd.core.v1.model.javasyntax.statement.Statements; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorDeclaration; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFieldDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileConstructorInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import org.jd.core.v1.util.DefaultList; import java.util.*; @@ -130,11 +127,11 @@ protected SuperConstructorInvocationExpression searchSuperConstructorCall(ListIt Expression expression = ((ExpressionStatement)statement).getExpression(); Class clazz = expression.getClass(); - if (clazz == SuperConstructorInvocationExpression.class) { + if (clazz == ClassFileSuperConstructorInvocationExpression.class) { return (SuperConstructorInvocationExpression)expression; } - if (clazz == ConstructorInvocationExpression.class) { + if (clazz == ClassFileConstructorInvocationExpression.class) { break; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java index 6c9f7130..9ba81c4f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -18,20 +18,15 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMemberDeclaration; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import java.util.Iterator; import java.util.List; public class RemoveDefaultConstructorVisitor extends AbstractJavaSyntaxVisitor { - protected SignatureParser signatureParser; protected int constructorCounter; protected ClassFileMemberDeclaration constructor; - public RemoveDefaultConstructorVisitor(SignatureParser signatureParser) { - this.signatureParser = signatureParser; - } - @Override public void visit(AnnotationDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); @@ -73,7 +68,7 @@ public void visit(ConstructorDeclaration declaration) { if (statement.getClass() == ExpressionStatement.class) { Expression es = ((ExpressionStatement) statement).getExpression(); - if (es.getClass() == SuperConstructorInvocationExpression.class) { + if (es.getClass() == ClassFileSuperConstructorInvocationExpression.class) { SuperConstructorInvocationExpression scie = (SuperConstructorInvocationExpression) es; if ("()V".equals(scie.getDescriptor())) { @@ -105,7 +100,7 @@ public void visit(ConstructorDeclaration declaration) { syntheticParameterCount++; } - if (signatureParser.parseParameterTypes(cfcd.getDescriptor()).size() == syntheticParameterCount) { + if (cfcd.getParameterTypes().size() == syntheticParameterCount) { constructor = cfcd; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java index 761d72e2..5771b7d9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -17,6 +17,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; import org.jd.core.v1.util.DefaultList; import java.util.HashMap; @@ -36,7 +37,7 @@ public boolean init(ClassFileBodyDeclaration bodyDeclaration) { @SuppressWarnings("unchecked") protected Expression updateExpression(Expression expression) { - if (expression.getClass() != MethodInvocationExpression.class) { + if (expression.getClass() != ClassFileMethodInvocationExpression.class) { return expression; } @@ -74,7 +75,7 @@ protected Expression updateExpression(Expression expression) { expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); return new FieldReferenceExpression(mie1.getLineNumber(), mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()); - } else if (expClass == MethodInvocationExpression.class) { + } else if (expClass == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie2 = (MethodInvocationExpression) exp; if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { @@ -229,7 +230,7 @@ private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMe } else if (parameterTypesCount == 1) { return (fre.getExpression() == null) || checkLocalVariableReference(fre.getExpression(), 0); } - } else if (expClass == MethodInvocationExpression.class) { + } else if (expClass == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie2 = (MethodInvocationExpression) exp; if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 640d5e91..d947dcea 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -14,6 +14,10 @@ import org.jd.core.v1.model.javasyntax.reference.ObjectReference; import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileConstructorInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileNewExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; import org.jd.core.v1.util.DefaultList; @@ -36,7 +40,6 @@ public class UpdateIntegerConstantTypeVisitor extends AbstractJavaSyntaxVisitor protected static final ObjectTypeReferenceExpression TYPE_SHORT_REFERENCE = new ObjectTypeReferenceExpression(ObjectType.TYPE_SHORT); protected static final ObjectTypeReferenceExpression TYPE_INTEGER_REFERENCE = new ObjectTypeReferenceExpression(ObjectType.TYPE_INTEGER); - protected SignatureParser signatureParser; protected Type returnedType; static { @@ -49,8 +52,7 @@ public class UpdateIntegerConstantTypeVisitor extends AbstractJavaSyntaxVisitor TYPES.put("java/lang/String:lastIndexOf(II)I", ci); } - public UpdateIntegerConstantTypeVisitor(SignatureParser signatureParser, Type returnedType) { - this.signatureParser = signatureParser; + public UpdateIntegerConstantTypeVisitor(Type returnedType) { this.returnedType = returnedType; } @@ -172,7 +174,7 @@ public void visit(SuperConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - expression.setParameters(updateExpressions(signatureParser.parseParameterTypes(expression.getDescriptor()), parameters)); + expression.setParameters(updateExpressions(((ClassFileSuperConstructorInvocationExpression)expression).getParameterTypes(), parameters)); } } @@ -181,7 +183,7 @@ public void visit(ConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - expression.setParameters(updateExpressions(signatureParser.parseParameterTypes(expression.getDescriptor()), parameters)); + expression.setParameters(updateExpressions(((ClassFileConstructorInvocationExpression)expression).getParameterTypes(), parameters)); } } @@ -196,7 +198,7 @@ public void visit(MethodInvocationExpression expression) { List types = TYPES.get(internalTypeName + ':' + name + descriptor); if (types == null) { - types = signatureParser.parseParameterTypes(descriptor); + types = ((ClassFileMethodInvocationExpression)expression).getParameterTypes(); } expression.setParameters(updateExpressions(types, parameters)); @@ -215,7 +217,7 @@ public void visit(NewExpression expression) { List types = TYPES.get(internalTypeName + ":" + descriptor); if (types == null) { - types = signatureParser.parseParameterTypes(descriptor); + types = ((ClassFileNewExpression)expression).getParameterTypes(); } expression.setParameters(updateExpressions(types, parameters)); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java new file mode 100644 index 00000000..3f1be740 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.declaration.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; + +public class UpdateJavaSyntaxTreeStep1Visitor extends AbstractJavaSyntaxVisitor { + protected InitInnerClassVisitor initInnerClassStep1Visitor = new InitInnerClassVisitor(); + + protected CreateInstructionsVisitor createInstructionsVisitor; + + public UpdateJavaSyntaxTreeStep1Visitor(ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser) { + createInstructionsVisitor = new CreateInstructionsVisitor(objectTypeMaker, signatureParser); + } + + @Override + public void visit(BodyDeclaration declaration) { + ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; + + // Visit inner types + if (bodyDeclaration.getInnerTypeDeclarations() != null) { + acceptListDeclaration(bodyDeclaration.getInnerTypeDeclarations()); + } + + // Visit declaration + createInstructionsVisitor.visit(declaration); + initInnerClassStep1Visitor.visit(declaration); + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java similarity index 79% rename from src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java rename to src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java index 02d4eb95..02557cac 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,36 +11,20 @@ import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileEnumDeclaration; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; - -public class UpdateJavaSyntaxTreeVisitor extends AbstractJavaSyntaxVisitor { +public class UpdateJavaSyntaxTreeStep2Visitor extends AbstractJavaSyntaxVisitor { protected static final AggregateFieldsVisitor AGGREGATE_FIELDS_VISITOR = new AggregateFieldsVisitor(); protected static final SortMembersVisitor SORT_MEMBERS_VISITOR = new SortMembersVisitor(); - protected InitInnerClassVisitor initInnerClassVisitor = new InitInnerClassVisitor(); + protected InitInnerClassVisitor.UpdateNewExpressionVisitor initInnerClassStep2Visitor = new InitInnerClassVisitor.UpdateNewExpressionVisitor(); protected InitStaticFieldVisitor initStaticFieldVisitor = new InitStaticFieldVisitor(); protected InitInstanceFieldVisitor initInstanceFieldVisitor = new InitInstanceFieldVisitor(); protected InitEnumVisitor initEnumVisitor = new InitEnumVisitor(); protected UpdateBridgeMethodVisitor replaceBridgeMethodVisitor = new UpdateBridgeMethodVisitor(); - - protected CreateInstructionsVisitor createInstructionsVisitor; - protected RemoveDefaultConstructorVisitor removeDefaultConstructorVisitor; + protected RemoveDefaultConstructorVisitor removeDefaultConstructorVisitor = new RemoveDefaultConstructorVisitor(); protected TypeDeclaration typeDeclaration; - public UpdateJavaSyntaxTreeVisitor(ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser) { - createInstructionsVisitor = new CreateInstructionsVisitor(objectTypeMaker, signatureParser); - removeDefaultConstructorVisitor = new RemoveDefaultConstructorVisitor(signatureParser); - } - - @Override - public void visit(AnnotationDeclaration declaration) { - this.typeDeclaration = declaration; - safeAccept(declaration.getBodyDeclaration()); - } - @Override public void visit(BodyDeclaration declaration) { ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; @@ -56,8 +40,7 @@ public void visit(BodyDeclaration declaration) { initStaticFieldVisitor.setInternalTypeName(typeDeclaration.getInternalName()); // Visit declaration - createInstructionsVisitor.visit(declaration); - initInnerClassVisitor.visit(declaration); + initInnerClassStep2Visitor.visit(declaration); initStaticFieldVisitor.visit(declaration); initInstanceFieldVisitor.visit(declaration); removeDefaultConstructorVisitor.visit(declaration); @@ -70,6 +53,12 @@ public void visit(BodyDeclaration declaration) { } } + @Override + public void visit(AnnotationDeclaration declaration) { + this.typeDeclaration = declaration; + safeAccept(declaration.getBodyDeclaration()); + } + @Override public void visit(ClassDeclaration declaration) { this.typeDeclaration = declaration; @@ -77,20 +66,21 @@ public void visit(ClassDeclaration declaration) { } @Override - public void visit(EnumDeclaration declaration) { - ClassFileEnumDeclaration cfed = (ClassFileEnumDeclaration)declaration; + public void visit(InterfaceDeclaration declaration) { + this.typeDeclaration = declaration; + safeAccept(declaration.getBodyDeclaration()); + } + @Override + public void visit(EnumDeclaration declaration) { this.typeDeclaration = declaration; + // Remove 'static' and 'final' flags + ClassFileEnumDeclaration cfed = (ClassFileEnumDeclaration)declaration; + cfed.setFlags(cfed.getFlags() ^ (Declaration.FLAG_STATIC|Declaration.FLAG_FINAL)); cfed.getBodyDeclaration().accept(this); initEnumVisitor.visit(cfed.getBodyDeclaration()); cfed.setConstants(initEnumVisitor.getConstants()); } - - @Override - public void visit(InterfaceDeclaration declaration) { - this.typeDeclaration = declaration; - safeAccept(declaration.getBodyDeclaration()); - } } diff --git a/src/test/java/org/jd/core/v1/TypeTest.java b/src/test/java/org/jd/core/v1/TypeTest.java index 4aa75ca1..169ff44d 100644 --- a/src/test/java/org/jd/core/v1/TypeTest.java +++ b/src/test/java/org/jd/core/v1/TypeTest.java @@ -37,7 +37,7 @@ public void testSimpleClassOrInterfaceType2() throws Exception { new ArrayTypeArguments( Arrays.asList( scoit1, - new WildcardTypeArgument(), + WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT, new WildcardSuperTypeArgument(scoit1), new WildcardExtendsTypeArgument(scoit1) ) From 686185be842a4eb7530f6e2f2a509dd62efe868d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 17 Aug 2019 22:47:18 +0200 Subject: [PATCH 068/211] Fix bug in identifying numeric constant types --- .../visitor/UpdateIntegerConstantTypeVisitor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index d947dcea..2b029332 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -144,11 +144,12 @@ public void visit(BinaryOperatorExpression expression) { expression.setLeftExpression(updateExpression(rightType, left)); right.accept(this); } + break; } else if (rightType.isPrimitive()) { left.accept(this); expression.setRightExpression(updateExpression(leftType, right)); + break; } - break; } left.accept(this); From c2962e68853c90d93a9f5fed3e70d8b6f1f639b7 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 18 Aug 2019 10:53:23 +0200 Subject: [PATCH 069/211] Improve recognition of switch-enum statements --- .../classfiletojavasyntax/util/StatementMaker.java | 2 +- .../util/SwitchStatementMaker.java | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 67187503..58e74fd8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -375,7 +375,7 @@ protected void parseSwitch(WatchDog watchdog, BasicBlock basicBlock, Statements< if ((size > 3) && (conditionClass == ClassFileLocalVariableReferenceExpression.class) && (statements.get(size-2).getClass() == SwitchStatement.class)) { // Check pattern & make 'switch-string' SwitchStatementMaker.makeSwitchString(localVariableMaker, statements, switchStatement); - } else if ((bodyDeclaration.getInnerTypeDeclarations() != null) && (conditionClass == ArrayExpression.class)) { + } else if (conditionClass == ArrayExpression.class) { // Check pattern & make 'switch-enum' SwitchStatementMaker.makeSwitchEnum(bodyDeclaration, switchStatement); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java index d657ca77..b783e897 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java @@ -187,13 +187,14 @@ public static void makeSwitchEnum(ClassFileBodyDeclaration bodyDeclaration, Swit FieldReferenceExpression fre = (FieldReferenceExpression)ae.getExpression(); if (fre.getDescriptor().equals("[I") && fre.getName().startsWith("$SwitchMap$")) { - // Javac switch-enum pattern - ClassFileClassDeclaration syntheticClass = (ClassFileClassDeclaration)bodyDeclaration.getInnerTypeDeclaration(fre.getInternalTypeName()); + ClassFileClassDeclaration syntheticClass = (ClassFileClassDeclaration)bodyDeclaration.getInnerTypeDeclaration(fre.getInternalTypeName()); - bodyDeclaration = (ClassFileBodyDeclaration)syntheticClass.getBodyDeclaration(); - - DefaultList statements = (DefaultList)bodyDeclaration.getMethodDeclarations().get(0).getStatements(); - updateSwitchStatement(switchStatement, statements.listIterator(1)); + if (syntheticClass != null) { + // Javac switch-enum pattern + bodyDeclaration = (ClassFileBodyDeclaration) syntheticClass.getBodyDeclaration(); + DefaultList statements = (DefaultList) bodyDeclaration.getMethodDeclarations().get(0).getStatements(); + updateSwitchStatement(switchStatement, statements.listIterator(1)); + } } } else if (expressionClass == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie = (MethodInvocationExpression)ae.getExpression(); From 73f08cffae534b5caaa5cadcc7f9986e6725f383 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 18 Aug 2019 15:01:17 +0200 Subject: [PATCH 070/211] Fix bug on parameters in 'this' and 'super' method invocations --- .../declaration/ClassDeclaration.java | 10 +- .../ClassFileClassDeclaration.java | 6 +- .../util/SignatureParser.java | 6 +- .../visitor/InitInnerClassVisitor.java | 108 +++++++----------- 4 files changed, 51 insertions(+), 79 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java index 08397647..670678bb 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -10,21 +10,21 @@ import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; -import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.ObjectType; public class ClassDeclaration extends InterfaceDeclaration { - protected Type superType; + protected ObjectType superType; public ClassDeclaration(int flags, String internalName, String name, BodyDeclaration bodyDeclaration) { super(null, flags, internalName, name, null, null, bodyDeclaration); } - public ClassDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, Type superType, BaseType interfaces, BodyDeclaration bodyDeclaration) { + public ClassDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, ObjectType superType, BaseType interfaces, BodyDeclaration bodyDeclaration) { super(annotationReferences, flags, internalName, name, typeParameters, interfaces, bodyDeclaration); this.superType = superType; } - public Type getSuperType() { + public ObjectType getSuperType() { return superType; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java index c13394e7..2e912010 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,12 +11,12 @@ import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; -import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.ObjectType; public class ClassFileClassDeclaration extends ClassDeclaration implements ClassFileMemberDeclaration { protected int firstLineNumber; - public ClassFileClassDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, Type superType, BaseType interfaces, ClassFileBodyDeclaration bodyDeclaration) { + public ClassFileClassDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, ObjectType superType, BaseType interfaces, ClassFileBodyDeclaration bodyDeclaration) { super(annotationReferences, flags, internalName, name, typeParameters, superType, interfaces, bodyDeclaration); this.firstLineNumber = bodyDeclaration==null ? 0 : bodyDeclaration.getFirstLineNumber(); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java index e72b14d0..9e1cde34 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java @@ -510,7 +510,7 @@ protected boolean isAReferenceTypeSignature(SignatureReader reader) { * SimpleClassTypeSignature: Identifier TypeArguments? * ClassTypeSignatureSuffix: '.' SimpleClassTypeSignature */ - protected Type parseClassTypeSignature(SignatureReader reader, int dimension) { + protected ObjectType parseClassTypeSignature(SignatureReader reader, int dimension) { if (reader.nextEqualsTo('L')) { // Skip 'L'. Parse 'PackageSpecifier* SimpleClassTypeSignature' int index = ++reader.index; @@ -570,7 +570,7 @@ protected Type parseClassTypeSignature(SignatureReader reader, int dimension) { // Skip ';' reader.index++; - return (dimension==0) ? ot : ot.createType(dimension); + return (dimension==0) ? ot : (ObjectType)ot.createType(dimension); } else { return null; } @@ -778,7 +778,7 @@ public String toString() { public static class TypeTypes { public ObjectType thisType; public BaseTypeParameter typeParameters; - public Type superType; + public ObjectType superType; public BaseType interfaces; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 4c9d70c5..099a0117 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -25,7 +25,7 @@ import java.util.*; public class InitInnerClassVisitor extends AbstractJavaSyntaxVisitor { - protected UpdateReferencesVisitor updateReferencesVisitor = new UpdateReferencesVisitor(); + protected UpdateFieldReferencesVisitor updateFieldReferencesVisitor = new UpdateFieldReferencesVisitor(); protected ObjectType outerType; protected DefaultList outerLocalVariableNames = new DefaultList<>(); @@ -63,7 +63,7 @@ public void visit(BodyDeclaration declaration) { bodyDeclaration.setOuterLocalVariableNames(outerLocalVariableNames.isEmpty() ? null : new DefaultList<>(outerLocalVariableNames)); if ((outerType != null) || !outerLocalVariableNames.isEmpty()) { - updateReferencesVisitor.visit(bodyDeclaration); + updateFieldReferencesVisitor.visit(bodyDeclaration); } } @@ -176,7 +176,7 @@ public void visit(MethodDeclaration declaration) {} @Override public void visit(StaticInitializerDeclaration declaration) {} - protected class UpdateReferencesVisitor extends AbstractJavaSyntaxVisitor { + protected class UpdateFieldReferencesVisitor extends AbstractJavaSyntaxVisitor { @Override public void visit(BodyDeclaration declaration) { ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; @@ -188,71 +188,6 @@ public void visit(MethodDeclaration declaration) { safeAccept(declaration.getStatements()); } - @Override - public void visit(StaticInitializerDeclaration declaration) { - safeAccept(declaration.getStatements()); - } - - @Override - public void visit(SuperConstructorInvocationExpression expression) { - SuperConstructorInvocationExpression cfscie = expression; - - if (cfscie.getParameters() != null) { - if (cfscie.getParameters().isList()) { - visitParameters(cfscie.getParameters().getList()); - } else { - cfscie.setParameters(visitParameter(cfscie.getParameters().getFirst())); - } - } - } - - @Override - public void visit(ConstructorInvocationExpression expression) { - ConstructorInvocationExpression cie = expression; - - assert cie.getParameters() != null; - - if (cie.getParameters().isList()) { - DefaultList parameters = cie.getParameters().getList(); - - parameters.remove(0); - assert parameters.size() > 0; - - if (parameters.size() == 1) { - cie.setParameters(visitParameter(parameters.getFirst())); - } else { - visitParameters(parameters); - } - } else { - cie.setParameters(null); - } - } - - @SuppressWarnings("unchecked") - protected void visitParameters(DefaultList list) { - ListIterator iterator = list.listIterator(); - - while (iterator.hasNext()) { - iterator.set(visitParameter(iterator.next())); - } - } - - protected Expression visitParameter(Expression expression) { - if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { - ClassFileLocalVariableReferenceExpression cflvre = (ClassFileLocalVariableReferenceExpression)expression; - - if (outerLocalVariableNames.contains(cflvre.getName())) { - return new FieldReferenceExpression(cflvre.getType(), new ObjectTypeReferenceExpression(cflvre.getLineNumber(), outerType), outerType.getInternalName(), cflvre.getName().substring(4), cflvre.getType().getDescriptor()); - } else if ((cflvre.getName() != null) && cflvre.getName().startsWith("this$") && cflvre.getType().getDescriptor().equals(outerType.getDescriptor())) { - return new FieldReferenceExpression(outerType, new ObjectTypeReferenceExpression(cflvre.getLineNumber(), outerType), outerType.getInternalName(), "this", outerType.getDescriptor()); - } - } else if (expression.getClass() == FieldReferenceExpression.class) { - expression.accept(this); - } - - return expression; - } - @Override public void visit(FieldReferenceExpression expression) { FieldReferenceExpression cffre = expression; @@ -299,6 +234,7 @@ public void visit(NewExpression expression) { public static class UpdateNewExpressionVisitor extends AbstractJavaSyntaxVisitor { protected ClassFileBodyDeclaration bodyDeclaration; + protected String superTypeName; protected HashMap finalLocalVariableNameMap = new HashMap<>(); protected DefaultList localClassDeclarations = new DefaultList<>(); protected HashSet newExpressions = new HashSet<>(); @@ -312,8 +248,10 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(ConstructorDeclaration declaration) { + superTypeName = ((ClassFileConstructorDeclaration)declaration).getClassFile().getSuperTypeName(); finalLocalVariableNameMap.clear(); localClassDeclarations.clear(); + safeAccept(declaration.getStatements()); if (! finalLocalVariableNameMap.isEmpty()) { @@ -507,6 +445,40 @@ public void visit(NewExpression expression) { } } + @Override + public void visit(SuperConstructorInvocationExpression expression) { + ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(superTypeName); + + if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { + ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; + ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); + + if (cfbd.getOuterType() != null) { + assert expression.getParameters().getFirst().getType().equals(cfbd.getOuterType()); + expression.setParameters(removeOuterThisParameter(expression.getParameters())); + } + } + } + + @Override + public void visit(ConstructorInvocationExpression expression) { + if (bodyDeclaration.getOuterType() != null) { + assert expression.getParameters().getFirst().getType().equals(bodyDeclaration.getOuterType()); + expression.setParameters(removeOuterThisParameter(expression.getParameters())); + } + } + + protected BaseExpression removeOuterThisParameter(BaseExpression parameters) { + // Remove outer this + if (parameters.isList()) { + parameters.getList().removeFirst(); + } else { + parameters = null; + } + + return parameters; + } + protected class UpdateFinalFieldReferenceVisitor extends AbstractJavaSyntaxVisitor { protected boolean fina1; From a94f5b9fa2297d3a7bbea4a333ae92c98a791d04 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 19 Aug 2019 12:11:27 +0200 Subject: [PATCH 071/211] Remove some outer local variable references --- .../visitor/InitInnerClassVisitor.java | 101 +++++++++--------- .../visitor/UpdateBridgeMethodVisitor.java | 13 ++- 2 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 099a0117..6837fdfa 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -133,11 +133,13 @@ public void visit(ConstructorDeclaration declaration) { int size = list.size(); list.subList(size - count, size).clear(); } - } else if (outerType != null) { + } else if ((outerType != null) || !outerLocalVariableNames.isEmpty()) { + // Remove outer this and outer local variable reference cfcd.setFormalParameters(null); } } + // Hide anonymous class constructor ClassFile outerClassFile = cfcd.getClassFile().getOuterClassFile(); if (outerClassFile != null) { @@ -170,65 +172,56 @@ public void visit(ConstructorDeclaration declaration) { } } - @Override - public void visit(MethodDeclaration declaration) {} - - @Override - public void visit(StaticInitializerDeclaration declaration) {} + @Override public void visit(MethodDeclaration declaration) {} + @Override public void visit(StaticInitializerDeclaration declaration) {} - protected class UpdateFieldReferencesVisitor extends AbstractJavaSyntaxVisitor { + protected class UpdateFieldReferencesVisitor extends AbstractUpdateExpressionVisitor { @Override public void visit(BodyDeclaration declaration) { - ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; - safeAcceptListDeclaration(bodyDeclaration.getMethodDeclarations()); + safeAcceptListDeclaration(((ClassFileBodyDeclaration)declaration).getMethodDeclarations()); } + @Override public void visit(StaticInitializerDeclaration declaration) {} + @Override public void visit(MethodDeclaration declaration) { safeAccept(declaration.getStatements()); } @Override - public void visit(FieldReferenceExpression expression) { - FieldReferenceExpression cffre = expression; - - if (outerLocalVariableNames.contains(expression.getName())) { - cffre.setName(cffre.getName().substring(4)); - cffre.setExpression(null); - } else if (cffre.getExpression() != null) { - Class clazz = cffre.getExpression().getClass(); - - if (clazz == FieldReferenceExpression.class) { - FieldReferenceExpression cffre2 = (FieldReferenceExpression) cffre.getExpression(); - - if (cffre2.getName().startsWith("this$") && cffre2.getDescriptor().equals(outerType.getDescriptor())) { - cffre.setExpression(new FieldReferenceExpression(outerType, new ObjectTypeReferenceExpression(cffre2.getLineNumber(), outerType), outerType.getInternalName(), "this", outerType.getDescriptor())); - } - } else if (clazz == ClassFileLocalVariableReferenceExpression.class) { - ClassFileLocalVariableReferenceExpression cdlvre = (ClassFileLocalVariableReferenceExpression) cffre.getExpression(); + public void visit(NewExpression expression) { + if (expression.getParameters() != null) { + expression.setParameters(updateBaseExpression(expression.getParameters())); + expression.getParameters().accept(this); + } + safeAccept(expression.getBodyDeclaration()); + } - if ((cdlvre.getName() != null) && cdlvre.getName().startsWith("this$") && cdlvre.getType().getDescriptor().equals(outerType.getDescriptor())) { - cffre.setExpression(new FieldReferenceExpression(outerType, new ObjectTypeReferenceExpression(cdlvre.getLineNumber(), outerType), outerType.getInternalName(), "this", outerType.getDescriptor())); - } - } else if (clazz == ThisExpression.class) { - if (cffre.getName().startsWith("this$") && cffre.getType().getDescriptor().equals(outerType.getDescriptor())) { - cffre.setExpression(new ObjectTypeReferenceExpression(cffre.getExpression().getLineNumber(), outerType)); - cffre.setName("this"); - } - } + @Override + public void visit(FieldReferenceExpression expression) { + if (expression.getName().startsWith("this$") && expression.getType().getDescriptor().equals(outerType.getDescriptor())) { + Expression exp = (expression.getExpression() == null) ? expression : expression.getExpression(); + expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), outerType)); + expression.setName("this"); + } else if (outerLocalVariableNames.contains(expression.getName())) { + expression.setName(expression.getName().substring(4)); + expression.setExpression(null); + } else { + super.visit(expression); } } @Override - public void visit(NewExpression expression) { - safeAccept(expression.getParameters()); - if (expression.getBodyDeclaration() != null) { - ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)expression.getBodyDeclaration(); + protected Expression updateExpression(Expression expression) { + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + ClassFileLocalVariableReferenceExpression cdlvre = (ClassFileLocalVariableReferenceExpression) expression; - for (ClassFileConstructorOrMethodDeclaration comd : bodyDeclaration.getMethodDeclarations()) { - safeAccept(comd.getStatements()); + if ((cdlvre.getName() != null) && cdlvre.getName().startsWith("this$") && cdlvre.getType().getDescriptor().equals(outerType.getDescriptor())) { + return new FieldReferenceExpression(outerType, new ObjectTypeReferenceExpression(cdlvre.getLineNumber(), outerType), outerType.getInternalName(), "this", outerType.getDescriptor()); } } + + return expression; } } @@ -447,24 +440,30 @@ public void visit(NewExpression expression) { @Override public void visit(SuperConstructorInvocationExpression expression) { - ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(superTypeName); + BaseExpression parameters = expression.getParameters(); + + if ((parameters != null) && (parameters.size() > 0)) { + ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(superTypeName); - if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { - ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; - ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); + if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { + ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; + ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); - if (cfbd.getOuterType() != null) { - assert expression.getParameters().getFirst().getType().equals(cfbd.getOuterType()); - expression.setParameters(removeOuterThisParameter(expression.getParameters())); + if (parameters.getFirst().getType().equals(cfbd.getOuterType())) { + expression.setParameters(removeOuterThisParameter(parameters)); + } } } } @Override public void visit(ConstructorInvocationExpression expression) { - if (bodyDeclaration.getOuterType() != null) { - assert expression.getParameters().getFirst().getType().equals(bodyDeclaration.getOuterType()); - expression.setParameters(removeOuterThisParameter(expression.getParameters())); + BaseExpression parameters = expression.getParameters(); + + if ((parameters != null) && (parameters.size() > 0)) { + if (parameters.getFirst().getType().equals(bodyDeclaration.getOuterType())) { + expression.setParameters(removeOuterThisParameter(parameters)); + } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java index 5771b7d9..a000a3a6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -152,6 +152,11 @@ protected Expression updateExpression(Expression expression) { protected class BodyDeclarationsVisitor extends AbstractJavaSyntaxVisitor { protected HashMap map = null; + @Override public void visit(ClassDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); } + @Override public void visit(EnumDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); } + @Override public void visit(InterfaceDeclaration declaration) {} + @Override public void visit(AnnotationDeclaration declaration) {} + @Override public void visit(BodyDeclaration declaration) { ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; @@ -174,6 +179,9 @@ public void visit(BodyDeclaration declaration) { safeAcceptListDeclaration(bodyDeclaration.getInnerTypeDeclarations()); } + @Override public void visit(StaticInitializerDeclaration declaration) {} + @Override public void visit(ConstructorDeclaration declaration) {} + @Override public void visit(MethodDeclaration declaration) { if ((declaration.getFlags() & FLAG_STATIC) == 0) { @@ -201,11 +209,6 @@ public void visit(MethodDeclaration declaration) { map.put(name + declaration.getDescriptor(), bridgeMethodDeclaration); } - @Override public void visit(ClassDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); } - @Override public void visit(EnumDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); } - @Override public void visit(InterfaceDeclaration declaration) {} - @Override public void visit(AnnotationDeclaration declaration) {} - private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMethodDeclaration) { Statement statement = bridgeMethodDeclaration.getStatements().getFirst(); Class statementClass = statement.getClass(); From f6b083718b74e70cf02b2c5b4e22f69fac88adaf Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 20 Aug 2019 13:50:34 +0200 Subject: [PATCH 072/211] Prepare refactoring of ObjectTypeMaker and SignatureParser --- .../util/AnnotationConverter.java | 12 ++--- .../util/ByteCodeParser.java | 35 ++++++--------- .../util/ObjectTypeMaker.java | 4 ++ .../UpdateIntegerConstantTypeVisitor.java | 1 - .../jd/core/v1/AnnotationConverterTest.java | 4 +- .../org/jd/core/v1/ControlFlowGraphTest.java | 19 ++++---- .../jd/core/v1/JarFileToJavaSourceTest.java | 8 ++-- .../org/jd/core/v1/SignatureParserTest.java | 44 +++++++++---------- 8 files changed, 60 insertions(+), 67 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java index 258c9fae..91bce239 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java @@ -17,11 +17,11 @@ import org.jd.core.v1.model.javasyntax.type.PrimitiveType; public class AnnotationConverter implements ElementValueVisitor { - protected ObjectTypeMaker factory; + protected ObjectTypeMaker objectTypeMaker; protected org.jd.core.v1.model.javasyntax.reference.ElementValue elementValue = null; - public AnnotationConverter(ObjectTypeMaker factory) { - this.factory = factory; + public AnnotationConverter(ObjectTypeMaker objectTypeMaker) { + this.objectTypeMaker = objectTypeMaker; } @SuppressWarnings("unchecked") @@ -73,7 +73,7 @@ protected AnnotationReference convert(Annotation annotation) { assert (descriptor != null) && (descriptor.length() > 2) && (descriptor.charAt(0) == 'L') && (descriptor.charAt(descriptor.length()-1) == ';'); - ObjectType ot = factory.makeFromDescriptor(descriptor); + ObjectType ot = objectTypeMaker.makeFromDescriptor(descriptor); ElementValuePair[] elementValuePairs = annotation.getElementValuePairs(); if (elementValuePairs == null) { @@ -145,7 +145,7 @@ public void visit(ElementValuePrimitiveType elementValuePrimitiveType) { @Override public void visit(ElementValueClassInfo elementValueClassInfo) { String classInfo = elementValueClassInfo.getClassInfo(); - ObjectType ot = factory.makeFromDescriptor(classInfo); + ObjectType ot = objectTypeMaker.makeFromDescriptor(classInfo); elementValue = new ExpressionElementValue(new TypeReferenceDotClassExpression(ot)); } @@ -162,7 +162,7 @@ public void visit(ElementValueEnumConstValue elementValueEnumConstValue) { assert (descriptor != null) && (descriptor.length() > 2) && (descriptor.charAt(0) == 'L') && (descriptor.charAt(descriptor.length()-1) == ';') : "AnnotationConverter.visit(elementValueEnumConstValue)"; - ObjectType ot = factory.makeFromDescriptor(descriptor); + ObjectType ot = objectTypeMaker.makeFromDescriptor(descriptor); String constName = elementValueEnumConstValue.getConstName(); String internalTypeName = descriptor.substring(1, descriptor.length()-1); elementValue = new ExpressionElementValue(new FieldReferenceExpression(ot, new ObjectTypeReferenceExpression(ot), internalTypeName, constName, descriptor)); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 1417421a..738131cd 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -88,7 +88,6 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau ConstantNameAndType constantNameAndType; String typeName, name, descriptor; ObjectType ot; - Type t; int i, count, value; AbstractLocalVariable localVariable; @@ -218,8 +217,8 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau valueRef = stack.pop(); indexRef = stack.pop(); arrayRef = stack.pop(); - t = arrayRef.getType(); - statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, t.createType(t.getDimension()-1), new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); + type1 = arrayRef.getType(); + statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, type1.createType(type1.getDimension()-1), new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); break; case 80: // LASTORE valueRef = stack.pop(); @@ -243,8 +242,8 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau valueRef = stack.pop(); indexRef = stack.pop(); arrayRef = stack.pop(); - t = arrayRef.getType(); - statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, t.createType(t.getDimension()>0 ? t.getDimension()-1 : 0), new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); + type1 = arrayRef.getType(); + statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, type1.createType(type1.getDimension()>0 ? type1.getDimension()-1 : 0), new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); break; case 84: // BASTORE valueRef = stack.pop(); @@ -722,9 +721,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 182: case 183: case 184: case 185: // INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ot = (typeName.charAt(0) == '[') ? - objectTypeMaker.makeFromDescriptor(typeName) : - objectTypeMaker.makeFromInternalTypeName(typeName); + ot = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); @@ -804,29 +801,25 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 192: // CHECKCAST typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - t = (typeName.charAt(0) == '[') ? - objectTypeMaker.makeFromDescriptor(typeName) : - objectTypeMaker.makeFromInternalTypeName(typeName); + type1 = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); expression1 = stack.pop(); if (expression1.getClass() == CastExpression.class) { // Skip double cast - ((CastExpression)expression1).setType(t); + ((CastExpression)expression1).setType(type1); } else { searchFirstLineNumberVisitor.init(); expression1.accept(searchFirstLineNumberVisitor); - expression1 = new CastExpression(searchFirstLineNumberVisitor.getLineNumber(), t, expression1); + expression1 = new CastExpression(searchFirstLineNumberVisitor.getLineNumber(), type1, expression1); } stack.push(expression1); break; case 193: // INSTANCEOF typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - t = (typeName.charAt(0) == '[') ? - objectTypeMaker.makeFromDescriptor(typeName) : - objectTypeMaker.makeFromInternalTypeName(typeName); - if (t == null) { - t = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); + type1 = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); + if (type1 == null) { + type1 = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); } - stack.push(new InstanceOfExpression(lineNumber, stack.pop(), t)); + stack.push(new InstanceOfExpression(lineNumber, stack.pop(), type1)); break; case 194: // MONITORENTER statements.add(new ClassFileMonitorEnterStatement(stack.pop())); @@ -998,9 +991,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in case Constant.CONSTANT_Class: int typeNameIndex = ((ConstantClass) constant).getNameIndex(); String typeName = ((ConstantUtf8)constants.getConstant(typeNameIndex)).getValue(); - Type type = (typeName.charAt(0) == '[') ? - objectTypeMaker.makeFromDescriptor(typeName) : - objectTypeMaker.makeFromInternalTypeName(typeName); + Type type = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); if (type == null) { type = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java index 3abb887c..cae9e74e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java @@ -113,6 +113,10 @@ public ObjectType makeFromInternalTypeName(String internalTypeName) { return ot; } + public ObjectType makeFromDescriptorOrInternalTypeName(String descriptorOrInternalTypeName) { + return (descriptorOrInternalTypeName.charAt(0) == '[') ? makeFromDescriptor(descriptorOrInternalTypeName) : makeFromInternalTypeName(descriptorOrInternalTypeName); + } + private ObjectType loadFromLoader(String internalTypeName) { try { ObjectType ot = internalTypeNameToObjectTypeCache.get(internalTypeName); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 2b029332..2adc9b9a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -19,7 +19,6 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileNewExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; import org.jd.core.v1.util.DefaultList; import java.util.AbstractList; diff --git a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java index b17fbcbc..b268cbfd 100644 --- a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java +++ b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java @@ -27,8 +27,8 @@ public class AnnotationConverterTest extends TestCase { public void test() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker factory = new ObjectTypeMaker(loader); - AnnotationConverter converter = new AnnotationConverter(factory); + ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + AnnotationConverter converter = new AnnotationConverter(objectTypeMaker); DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); Message message = new Message(); diff --git a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java index b3c35d8d..c91f4948 100644 --- a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java +++ b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java @@ -34,13 +34,12 @@ import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; - public class ControlFlowGraphTest extends TestCase { protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); protected ConvertClassFileProcessor converter = new ConvertClassFileProcessor(); protected ClassPathLoader loader = new ClassPathLoader(); - protected ObjectTypeMaker factory = new ObjectTypeMaker(loader); - protected SignatureParser parser = new SignatureParser(factory); + protected ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + protected SignatureParser signatureParser = new SignatureParser(objectTypeMaker); // --- Basic test ----------------------------------------------------------------------------------------------- // @Test @@ -2635,7 +2634,7 @@ protected InputStream loadFile(String zipName) throws IOException { } protected Method searchMethod(String internalTypeName, String methodName) throws Exception { - return searchMethod(loader, factory, parser, internalTypeName, methodName, null); + return searchMethod(loader, objectTypeMaker, signatureParser, internalTypeName, methodName, null); } protected Method searchMethod(InputStream is, String internalTypeName, String methodName) throws Exception { @@ -2647,18 +2646,18 @@ protected Method searchMethod(InputStream is, String internalTypeName, String me return null; } else { ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker factory = new ObjectTypeMaker(loader); - SignatureParser parser = new SignatureParser(factory); - return searchMethod(loader, factory, parser, internalTypeName, methodName, methodDescriptor); + ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + SignatureParser signatureParser = new SignatureParser(objectTypeMaker); + return searchMethod(loader, objectTypeMaker, signatureParser, internalTypeName, methodName, methodDescriptor); } } - protected Method searchMethod(Loader loader, ObjectTypeMaker factory, SignatureParser parser, String internalTypeName, String methodName, String methodDescriptor) throws Exception { + protected Method searchMethod(Loader loader, ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, String internalTypeName, String methodName, String methodDescriptor) throws Exception { Message message = new Message(); message.setHeader("mainInternalTypeName", internalTypeName); message.setHeader("loader", loader); - message.setHeader("objectTypeMaker", factory); - message.setHeader("signatureParser", parser); + message.setHeader("objectTypeMaker", objectTypeMaker); + message.setHeader("signatureParser", signatureParser); deserializer.process(message); converter.process(message); diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 7fe47388..c5e95084 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -95,9 +95,9 @@ protected void test(InputStream inputStream) throws Exception { // Recompile source String source = printer.toString(); - // TODO if (!CompilerUtil.compile("1.8", new JavaSourceFileObject(internalTypeName, source))) { - // TODO recompilationFailedCounter++; - // TODO } + if (!CompilerUtil.compile("1.8", new JavaSourceFileObject(internalTypeName, source))) { + recompilationFailedCounter++; + } } } @@ -128,7 +128,7 @@ protected void test(InputStream inputStream) throws Exception { assertTrue(exceptionCounter == 0); assertTrue(assertFailedCounter == 0); - // TODO assertTrue(recompilationFailedCounter == 0); + assertTrue(recompilationFailedCounter == 0); } } diff --git a/src/test/java/org/jd/core/v1/SignatureParserTest.java b/src/test/java/org/jd/core/v1/SignatureParserTest.java index 5e5b55ab..aa810454 100644 --- a/src/test/java/org/jd/core/v1/SignatureParserTest.java +++ b/src/test/java/org/jd/core/v1/SignatureParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -31,8 +31,8 @@ public void testAnnotatedClass() throws Exception { PrintTypeVisitor visitor = new PrintTypeVisitor(); InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker factory = new ObjectTypeMaker(loader); - SignatureParser parser = new SignatureParser(factory); + ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + SignatureParser signatureParser = new SignatureParser(objectTypeMaker); Message message = new Message(); message.setHeader("mainInternalTypeName", "org/jd/core/test/AnnotatedClass"); @@ -43,7 +43,7 @@ public void testAnnotatedClass() throws Exception { ClassFile classFile = message.getBody(); // Check type - SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + SignatureParser.TypeTypes typeTypes = signatureParser.parseClassFileSignature(classFile); // Check type parameterTypes assertNull(typeTypes.typeParameters); @@ -66,7 +66,7 @@ public void testAnnotatedClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = parser.parseFieldSignature(classFile.getFields()[0]); + Type type = signatureParser.parseFieldSignature(classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -75,7 +75,7 @@ public void testAnnotatedClass() throws Exception { // Check method 'add' // public int add(int i1, int i2) - SignatureParser.MethodTypes methodTypes = parser.parseMethodSignature(classFile.getMethods()[1]); + SignatureParser.MethodTypes methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[1]); // Check type parameterTypes assertNull(methodTypes.typeParameters); @@ -105,7 +105,7 @@ public void testAnnotatedClass() throws Exception { // Check method 'ping' // public void ping(String host) throws UnknownHostException, UnsatisfiedLinkError - methodTypes = parser.parseMethodSignature(classFile.getMethods()[2]); + methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[2]); // Check type parameterTypes assertNull(methodTypes.typeParameters); @@ -145,8 +145,8 @@ public void testGenericClass() throws Exception { PrintTypeVisitor visitor = new PrintTypeVisitor(); InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker factory = new ObjectTypeMaker(loader); - SignatureParser parser = new SignatureParser(factory); + ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + SignatureParser signatureParser = new SignatureParser(objectTypeMaker); Message message = new Message(); message.setHeader("mainInternalTypeName", "org/jd/core/test/GenericClass"); @@ -157,7 +157,7 @@ public void testGenericClass() throws Exception { ClassFile classFile = message.getBody(); // Check type - SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + SignatureParser.TypeTypes typeTypes = signatureParser.parseClassFileSignature(classFile); // Check type parameterTypes // See "org.jd.core.test.resources.java.Generic" @@ -205,7 +205,7 @@ public void testGenericClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = parser.parseFieldSignature(classFile.getFields()[0]); + Type type = signatureParser.parseFieldSignature(classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -214,7 +214,7 @@ public void testGenericClass() throws Exception { // Check method 'copy2' // public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException - SignatureParser.MethodTypes methodTypes = parser.parseMethodSignature(classFile.getMethods()[3]); + SignatureParser.MethodTypes methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[3]); // Check type parameterTypes assertNotNull(methodTypes.typeParameters); @@ -255,7 +255,7 @@ public void testGenericClass() throws Exception { // Check method 'print' // public List print(List list) throws InvalidParameterException, T2 - methodTypes = parser.parseMethodSignature(classFile.getMethods()[4]); + methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[4]); // Check type parameterTypes assertNotNull(methodTypes.typeParameters); @@ -299,30 +299,30 @@ public void testGenericClass() throws Exception { public void testParseReturnedVoid() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker factory = new ObjectTypeMaker(loader); - SignatureParser parser = new SignatureParser(factory); + ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + SignatureParser signatureParser = new SignatureParser(objectTypeMaker); - Assert.assertEquals(parser.parseReturnedType("()V"), PrimitiveType.TYPE_VOID); + Assert.assertEquals(signatureParser.parseReturnedType("()V"), PrimitiveType.TYPE_VOID); } @Test public void testParseReturnedPrimitiveType() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker factory = new ObjectTypeMaker(loader); - SignatureParser parser = new SignatureParser(factory); + ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + SignatureParser signatureParser = new SignatureParser(objectTypeMaker); - Assert.assertEquals(parser.parseReturnedType("()Z"), PrimitiveType.TYPE_BOOLEAN); + Assert.assertEquals(signatureParser.parseReturnedType("()Z"), PrimitiveType.TYPE_BOOLEAN); } @Test public void testParseReturnedStringType() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker factory = new ObjectTypeMaker(loader); - SignatureParser parser = new SignatureParser(factory); + ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); + SignatureParser signatureParser = new SignatureParser(objectTypeMaker); - Assert.assertEquals(parser.parseReturnedType("()Ljava/lang/String;"), ObjectType.TYPE_STRING); + Assert.assertEquals(signatureParser.parseReturnedType("()Ljava/lang/String;"), ObjectType.TYPE_STRING); } From afd3af5406229aca21df8d3eb7c00d8f72c25f8b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 20 Aug 2019 14:55:12 +0200 Subject: [PATCH 073/211] Merge ObjectTypeMaker and SignatureParser --- .../ClassFileToJavaSyntaxProcessor.java | 11 +- .../localvariable/ObjectLocalVariable.java | 22 +- .../processor/ConvertClassFileProcessor.java | 50 +- .../UpdateJavaSyntaxTreeProcessor.java | 8 +- .../util/AnnotationConverter.java | 12 +- .../util/ByteCodeParser.java | 56 +- .../util/LocalVariableMaker.java | 46 +- .../util/ObjectTypeMaker.java | 498 ---------------- .../util/StatementMaker.java | 16 +- .../{SignatureParser.java => TypeMaker.java} | 554 ++++++++++++++++-- .../visitor/CreateInstructionsVisitor.java | 19 +- .../visitor/CreateLocalVariableVisitor.java | 18 +- .../visitor/CreateParameterVisitor.java | 16 +- .../visitor/InitEnumVisitor.java | 4 +- .../visitor/InitInnerClassVisitor.java | 4 +- .../UpdateJavaSyntaxTreeStep1Visitor.java | 7 +- .../jd/core/v1/AnnotationConverterTest.java | 6 +- .../org/jd/core/v1/ControlFlowGraphTest.java | 15 +- .../org/jd/core/v1/ObjectTypeMakerTest.java | 86 +-- .../org/jd/core/v1/SignatureParserTest.java | 82 ++- 20 files changed, 735 insertions(+), 795 deletions(-) delete mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ObjectTypeMaker.java rename src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/{SignatureParser.java => TypeMaker.java} (53%) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java index 495812fb..a0136c67 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -12,8 +12,7 @@ import org.jd.core.v1.model.processor.Processor; import org.jd.core.v1.service.converter.classfiletojavasyntax.processor.ConvertClassFileProcessor; import org.jd.core.v1.service.converter.classfiletojavasyntax.processor.UpdateJavaSyntaxTreeProcessor; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; /** * Convert ClassFile model to Java syntax model.

@@ -30,11 +29,9 @@ public class ClassFileToJavaSyntaxProcessor implements Processor { public void process(Message message) throws Exception { Loader loader = message.getHeader("loader"); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - SignatureParser parser = new SignatureParser(maker); + TypeMaker typeMaker = new TypeMaker(loader); - message.setHeader("objectTypeMaker", maker); - message.setHeader("signatureParser", parser); + message.setHeader("typeMaker", typeMaker); CONVERT_CLASS_FILE_PROCESSOR.process(message); UPDATE_JAVA_SYNTAX_TREE_PROCESSOR.process(message); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index e8062164..72ea9513 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -9,29 +9,29 @@ import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; public class ObjectLocalVariable extends AbstractLocalVariable { - protected ObjectTypeMaker objectTypeMaker; + protected TypeMaker typeMaker; protected Type type; - public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, Type type, String name) { + public ObjectLocalVariable(TypeMaker typeMaker, int index, int offset, Type type, String name) { super(index, offset, name); - this.objectTypeMaker = objectTypeMaker; + this.typeMaker = typeMaker; this.type = type; } - public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, Type type, String name, boolean declared) { - this(objectTypeMaker, index, offset, type, name); + public ObjectLocalVariable(TypeMaker typeMaker, int index, int offset, Type type, String name, boolean declared) { + this(typeMaker, index, offset, type, name); this.declared = declared; } - public ObjectLocalVariable(ObjectTypeMaker objectTypeMaker, int index, int offset, ObjectLocalVariable objectLocalVariable) { + public ObjectLocalVariable(TypeMaker typeMaker, int index, int offset, ObjectLocalVariable objectLocalVariable) { super(index, offset, null); - this.objectTypeMaker = objectTypeMaker; + this.typeMaker = typeMaker; this.type = objectLocalVariable.type; } @@ -94,7 +94,7 @@ public boolean isAssignableFrom(Type type) { if (type.getDimension() == 0) { if ((thisObjectType.getTypeArguments() == null) ? (otherObjectType.getTypeArguments() == null) : thisObjectType.getTypeArguments().equals(otherObjectType.getTypeArguments())) { - return objectTypeMaker.isAssignable(thisObjectType, otherObjectType); + return typeMaker.isAssignable(thisObjectType, otherObjectType); } } } else if (thisObjectType.getInternalName().equals(TYPE_OBJECT.getInternalName())) { @@ -126,7 +126,7 @@ public void typeOnRight(Type type) { this.type = otherObjectType; fireChangeEvent(); } - } else if (objectTypeMaker.isAssignable(thisObjectType, otherObjectType)) { + } else if (typeMaker.isAssignable(thisObjectType, otherObjectType)) { // Assignable types if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { // Keep type, update type arguments @@ -163,7 +163,7 @@ public void typeOnLeft(Type type) { this.type = otherObjectType; fireChangeEvent(); } - } else if (objectTypeMaker.isAssignable(otherObjectType, thisObjectType)) { + } else if (typeMaker.isAssignable(otherObjectType, thisObjectType)) { // Assignable types if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { // Keep type, update type arguments diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index 2da27ce9..af2874d1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -23,8 +23,7 @@ import org.jd.core.v1.model.processor.Processor; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.AnnotationConverter; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.util.DefaultList; import java.util.List; @@ -39,25 +38,24 @@ public class ConvertClassFileProcessor implements Processor { @Override public void process(Message message) throws Exception { - ObjectTypeMaker objectTypeMaker = message.getHeader("objectTypeMaker"); - SignatureParser signatureParser = message.getHeader("signatureParser"); + TypeMaker typeMaker = message.getHeader("typeMaker"); ClassFile classFile = message.getBody(); - AnnotationConverter annotationConverter = new AnnotationConverter(objectTypeMaker); + AnnotationConverter annotationConverter = new AnnotationConverter(typeMaker); int flags = classFile.getAccessFlags(); TypeDeclaration typeDeclaration; if ((flags & Constants.ACC_ENUM) != 0) { - typeDeclaration = convertEnumDeclaration(signatureParser, annotationConverter, classFile, null); + typeDeclaration = convertEnumDeclaration(typeMaker, annotationConverter, classFile, null); } else if ((flags & Constants.ACC_ANNOTATION) != 0) { - typeDeclaration = convertAnnotationDeclaration(signatureParser, annotationConverter, classFile, null); + typeDeclaration = convertAnnotationDeclaration(typeMaker, annotationConverter, classFile, null); } else if ((flags & Constants.ACC_MODULE) != 0) { typeDeclaration = convertModuleDeclaration(classFile); } else if ((flags & Constants.ACC_INTERFACE) != 0) { - typeDeclaration = convertInterfaceDeclaration(signatureParser, annotationConverter, classFile, null); + typeDeclaration = convertInterfaceDeclaration(typeMaker, annotationConverter, classFile, null); } else { - typeDeclaration = convertClassDeclaration(signatureParser, annotationConverter, classFile, null); + typeDeclaration = convertClassDeclaration(typeMaker, annotationConverter, classFile, null); } message.setHeader("majorVersion", classFile.getMajorVersion()); @@ -65,9 +63,9 @@ public void process(Message message) throws Exception { message.setBody(new CompilationUnit(typeDeclaration)); } - protected ClassFileInterfaceDeclaration convertInterfaceDeclaration(SignatureParser parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + protected ClassFileInterfaceDeclaration convertInterfaceDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); - SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); return new ClassFileInterfaceDeclaration( @@ -76,9 +74,9 @@ protected ClassFileInterfaceDeclaration convertInterfaceDeclaration(SignaturePar typeTypes.typeParameters, typeTypes.interfaces, bodyDeclaration); } - protected ClassFileEnumDeclaration convertEnumDeclaration(SignatureParser parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + protected ClassFileEnumDeclaration convertEnumDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); - SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); return new ClassFileEnumDeclaration( @@ -87,9 +85,9 @@ protected ClassFileEnumDeclaration convertEnumDeclaration(SignatureParser parser typeTypes.interfaces, bodyDeclaration); } - protected ClassFileAnnotationDeclaration convertAnnotationDeclaration(SignatureParser parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + protected ClassFileAnnotationDeclaration convertAnnotationDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); - SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); return new ClassFileAnnotationDeclaration( @@ -98,9 +96,9 @@ protected ClassFileAnnotationDeclaration convertAnnotationDeclaration(SignatureP bodyDeclaration); } - protected ClassFileClassDeclaration convertClassDeclaration(SignatureParser parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + protected ClassFileClassDeclaration convertClassDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); - SignatureParser.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); + TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); return new ClassFileClassDeclaration( @@ -110,7 +108,7 @@ protected ClassFileClassDeclaration convertClassDeclaration(SignatureParser pars typeTypes.interfaces, bodyDeclaration); } - protected ClassFileBodyDeclaration convertBodyDeclaration(SignatureParser parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + protected ClassFileBodyDeclaration convertBodyDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile.getInternalTypeName(), outerClassFileBodyDeclaration); bodyDeclaration.setFieldDeclarations(convertFields(parser, converter, classFile)); @@ -120,7 +118,7 @@ protected ClassFileBodyDeclaration convertBodyDeclaration(SignatureParser parser return bodyDeclaration; } - protected List convertFields(SignatureParser parser, AnnotationConverter converter, ClassFile classFile) { + protected List convertFields(TypeMaker parser, AnnotationConverter converter, ClassFile classFile) { Field[] fields = classFile.getFields(); if (fields == null) { @@ -141,7 +139,7 @@ protected List convertFields(SignatureParser parser, } } - protected List convertMethods(SignatureParser parser, AnnotationConverter converter, ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile) { + protected List convertMethods(TypeMaker parser, AnnotationConverter converter, ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile) { Method[] methods = classFile.getMethods(); if (methods == null) { @@ -170,18 +168,18 @@ protected List convertMethods(Signature } if ("".equals(name)) { - SignatureParser.MethodTypes methodTypes = parser.parseConstructorSignature(method); + TypeMaker.MethodTypes methodTypes = parser.parseConstructorSignature(method); list.add(new ClassFileConstructorDeclaration( bodyDeclaration, classFile, method, annotationReferences, methodTypes.typeParameters, - methodTypes.parameters, methodTypes.exceptions, firstLineNumber)); + methodTypes.parameterTypes, methodTypes.exceptions, firstLineNumber)); } else if ("".equals(name)) { list.add(new ClassFileStaticInitializerDeclaration(bodyDeclaration, classFile, method, firstLineNumber)); } else { ClassFileMethodDeclaration methodDeclaration; - SignatureParser.MethodTypes methodTypes = parser.parseMethodSignature(method); + TypeMaker.MethodTypes methodTypes = parser.parseMethodSignature(method); list.add(methodDeclaration = new ClassFileMethodDeclaration( bodyDeclaration, classFile, method, annotationReferences, name, methodTypes.typeParameters, - methodTypes.returned, methodTypes.parameters, methodTypes.exceptions, defaultAnnotationValue, + methodTypes.returnedType, methodTypes.parameterTypes, methodTypes.exceptions, defaultAnnotationValue, firstLineNumber)); if ((classFile.getAccessFlags() & Constants.ACC_INTERFACE) != 0) { if (methodDeclaration.getFlags() == Constants.ACC_PUBLIC) { @@ -196,7 +194,7 @@ protected List convertMethods(Signature } } - protected List convertInnerTypes(SignatureParser parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + protected List convertInnerTypes(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { List innerClassFiles = classFile.getInnerClassFiles(); if (innerClassFiles == null) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java index 1a8d617c..0cc5dc4c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java @@ -10,8 +10,7 @@ import org.jd.core.v1.model.javasyntax.CompilationUnit; import org.jd.core.v1.model.message.Message; import org.jd.core.v1.model.processor.Processor; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.UpdateJavaSyntaxTreeStep1Visitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.UpdateJavaSyntaxTreeStep2Visitor; @@ -25,11 +24,10 @@ public class UpdateJavaSyntaxTreeProcessor implements Processor { @Override public void process(Message message) throws Exception { - ObjectTypeMaker maker = message.getHeader("objectTypeMaker"); - SignatureParser parser = message.getHeader("signatureParser"); + TypeMaker typeMaker = message.getHeader("typeMaker"); CompilationUnit compilationUnit = message.getBody(); - UpdateJavaSyntaxTreeStep1Visitor updateJavaSyntaxTreeStep1Visitor = new UpdateJavaSyntaxTreeStep1Visitor(maker, parser); + UpdateJavaSyntaxTreeStep1Visitor updateJavaSyntaxTreeStep1Visitor = new UpdateJavaSyntaxTreeStep1Visitor(typeMaker); updateJavaSyntaxTreeStep1Visitor.visit(compilationUnit); UpdateJavaSyntaxTreeStep2Visitor updateJavaSyntaxTreeStep2Visitor = new UpdateJavaSyntaxTreeStep2Visitor(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java index 91bce239..ee8f0b8e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AnnotationConverter.java @@ -17,11 +17,11 @@ import org.jd.core.v1.model.javasyntax.type.PrimitiveType; public class AnnotationConverter implements ElementValueVisitor { - protected ObjectTypeMaker objectTypeMaker; + protected TypeMaker typeMaker; protected org.jd.core.v1.model.javasyntax.reference.ElementValue elementValue = null; - public AnnotationConverter(ObjectTypeMaker objectTypeMaker) { - this.objectTypeMaker = objectTypeMaker; + public AnnotationConverter(TypeMaker typeMaker) { + this.typeMaker = typeMaker; } @SuppressWarnings("unchecked") @@ -73,7 +73,7 @@ protected AnnotationReference convert(Annotation annotation) { assert (descriptor != null) && (descriptor.length() > 2) && (descriptor.charAt(0) == 'L') && (descriptor.charAt(descriptor.length()-1) == ';'); - ObjectType ot = objectTypeMaker.makeFromDescriptor(descriptor); + ObjectType ot = typeMaker.makeFromDescriptor(descriptor); ElementValuePair[] elementValuePairs = annotation.getElementValuePairs(); if (elementValuePairs == null) { @@ -145,7 +145,7 @@ public void visit(ElementValuePrimitiveType elementValuePrimitiveType) { @Override public void visit(ElementValueClassInfo elementValueClassInfo) { String classInfo = elementValueClassInfo.getClassInfo(); - ObjectType ot = objectTypeMaker.makeFromDescriptor(classInfo); + ObjectType ot = typeMaker.makeFromDescriptor(classInfo); elementValue = new ExpressionElementValue(new TypeReferenceDotClassExpression(ot)); } @@ -162,7 +162,7 @@ public void visit(ElementValueEnumConstValue elementValueEnumConstValue) { assert (descriptor != null) && (descriptor.length() > 2) && (descriptor.charAt(0) == 'L') && (descriptor.charAt(descriptor.length()-1) == ';') : "AnnotationConverter.visit(elementValueEnumConstValue)"; - ObjectType ot = objectTypeMaker.makeFromDescriptor(descriptor); + ObjectType ot = typeMaker.makeFromDescriptor(descriptor); String constName = elementValueEnumConstValue.getConstName(); String internalTypeName = descriptor.substring(1, descriptor.length()-1); elementValue = new ExpressionElementValue(new FieldReferenceExpression(ot, new ObjectTypeReferenceExpression(ot), internalTypeName, constName, descriptor)); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 738131cd..9300d04e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -49,8 +49,7 @@ public class ByteCodeParser { private static final JsrReturnAddressExpression JSR_RETURN_ADDRESS_EXPRESSION = new JsrReturnAddressExpression(); - private ObjectTypeMaker objectTypeMaker; - private SignatureParser signatureParser; + private TypeMaker typeMaker; private LocalVariableMaker localVariableMaker; private String internalTypeName; private AttributeBootstrapMethods attributeBootstrapMethods; @@ -61,10 +60,9 @@ public class ByteCodeParser { private SearchWildcardTypeArgumentVisitor searchWildcardTypeArgumentVisitor = new SearchWildcardTypeArgumentVisitor(); public ByteCodeParser( - ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, LocalVariableMaker localVariableMaker, - String internalTypeName, ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration, Type returnedType) { - this.objectTypeMaker = objectTypeMaker; - this.signatureParser = signatureParser; + TypeMaker typeMaker, LocalVariableMaker localVariableMaker, String internalTypeName, + ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration, Type returnedType) { + this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; this.internalTypeName = internalTypeName; this.attributeBootstrapMethods = classFile.getAttribute("BootstrapMethods"); @@ -721,13 +719,13 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 182: case 183: case 184: case 185: // INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ot = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); + ot = typeMaker.makeFromDescriptorOrInternalTypeName(typeName); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - DefaultList parameterTypes = signatureParser.parseParameterTypes(descriptor); + DefaultList parameterTypes = typeMaker.parseParameterTypes(descriptor); BaseExpression parameters = getParameters(statements, stack, parameterTypes); - Type returnedType = signatureParser.parseReturnedType(descriptor); + Type returnedType = typeMaker.parseReturnedType(descriptor); if (opcode == 184) { // INVOKESTATIC expression1 = new ClassFileMethodInvocationExpression(lineNumber, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameterTypes, parameters); @@ -786,10 +784,10 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 189: // ANEWARRAY typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); if (typeName.charAt(0) == '[') { - type1 = objectTypeMaker.makeFromDescriptor(typeName); + type1 = typeMaker.makeFromDescriptor(typeName); type1 = type1.createType(type1.getDimension()+1); } else { - type1 = objectTypeMaker.makeFromInternalTypeName(typeName).createType(1); + type1 = typeMaker.makeFromInternalTypeName(typeName).createType(1); } stack.push(new NewArray(lineNumber, type1, stack.pop())); break; @@ -801,7 +799,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 192: // CHECKCAST typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - type1 = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); + type1 = typeMaker.makeFromDescriptorOrInternalTypeName(typeName); expression1 = stack.pop(); if (expression1.getClass() == CastExpression.class) { // Skip double cast @@ -815,7 +813,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 193: // INSTANCEOF typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - type1 = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); + type1 = typeMaker.makeFromDescriptorOrInternalTypeName(typeName); if (type1 == null) { type1 = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); } @@ -870,7 +868,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 197: // MULTIANEWARRAY typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); - type1 = objectTypeMaker.makeFromDescriptor(typeName); + type1 = typeMaker.makeFromDescriptor(typeName); i = code[++offset] & 255; Expressions dimensions = new Expressions(i); @@ -991,7 +989,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in case Constant.CONSTANT_Class: int typeNameIndex = ((ConstantClass) constant).getNameIndex(); String typeName = ((ConstantUtf8)constants.getConstant(typeNameIndex)).getValue(); - Type type = objectTypeMaker.makeFromDescriptorOrInternalTypeName(typeName); + Type type = typeMaker.makeFromDescriptorOrInternalTypeName(typeName); if (type == null) { type = PrimitiveTypeUtil.getPrimitiveTypeFromDescriptor(typeName); } @@ -1267,9 +1265,9 @@ private void parseInvokeDynamic(Statements statements, DefaultStack indyParameterTypes = signatureParser.parseParameterTypes(indyDescriptor); + DefaultList indyParameterTypes = typeMaker.parseParameterTypes(indyDescriptor); BaseExpression indyParameters = getParameters(statements, stack, indyParameterTypes); - Type indyReturnType = signatureParser.parseReturnedType(indyDescriptor); + Type indyReturnType = typeMaker.parseReturnedType(indyDescriptor); BootstrapMethod bootstrapMethod = attributeBootstrapMethods.getBootstrapMethods()[constantMemberRef.getClassIndex()]; int[] bootstrapArguments = bootstrapMethod.getBootstrapArguments(); @@ -1287,8 +1285,8 @@ private void parseInvokeDynamic(Statements statements, DefaultStack statements, DefaultStack")) { stack.push(new ConstructorReferenceExpression(lineNumber, indyReturnType, ot, descriptor1)); @@ -1655,8 +1653,8 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan } String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = signatureParser.parseTypeSignature(descriptor); - ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); + Type type = typeMaker.parseTypeSignature(descriptor); + ObjectType ot = typeMaker.makeFromInternalTypeName(typeName); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); stack.push(new FieldReferenceExpression(lineNumber, type, objectRef, typeName, name, descriptor)); } @@ -1664,11 +1662,11 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan private void parsePutStatic(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); + ObjectType ot = typeMaker.makeFromInternalTypeName(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = signatureParser.parseTypeSignature(descriptor); + Type type = typeMaker.parseTypeSignature(descriptor); Expression valueRef = stack.pop(); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); FieldReferenceExpression fieldRef = new FieldReferenceExpression(lineNumber, type, objectRef, typeName, name, descriptor); @@ -1678,11 +1676,11 @@ private void parsePutStatic(Statements statements, DefaultStack stac private void parseGetField(DefaultStack stack, ConstantPool constants, int lineNumber, int index) { ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); + ObjectType ot = typeMaker.makeFromInternalTypeName(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = signatureParser.parseTypeSignature(descriptor); + Type type = typeMaker.parseTypeSignature(descriptor); Expression objectRef = stack.pop(); stack.push(new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor)); } @@ -1690,11 +1688,11 @@ private void parseGetField(DefaultStack stack, ConstantPool constant private void parsePutField(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName); + ObjectType ot = typeMaker.makeFromInternalTypeName(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = signatureParser.parseTypeSignature(descriptor); + Type type = typeMaker.parseTypeSignature(descriptor); Expression valueRef = stack.pop(); Expression objectRef = stack.pop(); FieldReferenceExpression fieldRef = new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor); @@ -1716,7 +1714,7 @@ private static Expression getLastRightExpression(BinaryOperatorExpression boe) { } private Expression newNewExpression(int lineNumber, String internalName) { - ObjectType objectType = objectTypeMaker.makeFromInternalTypeName(internalName); + ObjectType objectType = typeMaker.makeFromInternalTypeName(internalName); if ((objectType.getQualifiedName() == null) && (objectType.getName() == null)) { ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 22337e7a..e7d8c37e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -37,8 +37,7 @@ public class LocalVariableMaker { protected Frame currentFrame = new RootFrame(); protected AbstractLocalVariable[] localVariableCache; - protected ObjectTypeMaker objectTypeMaker; - protected SignatureParser signatureParser; + protected TypeMaker typeMaker; protected FormalParameters formalParameters; protected PopulateBlackListNamesVisitor populateBlackListNamesVisitor = new PopulateBlackListNamesVisitor(blackListNames); @@ -46,14 +45,13 @@ public class LocalVariableMaker { protected CreateLocalVariableVisitor createLocalVariableVisitor; @SuppressWarnings("unchecked") - public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, ClassFileConstructorOrMethodDeclaration comdwln, boolean constructor, List parameterTypes) { + public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDeclaration comdwln, boolean constructor, List parameterTypes) { ClassFile classFile = comdwln.getClassFile(); Method method = comdwln.getMethod(); - this.objectTypeMaker = objectTypeMaker; - this.signatureParser = signatureParser; - this.createParameterVisitor = new CreateParameterVisitor(objectTypeMaker); - this.createLocalVariableVisitor = new CreateLocalVariableVisitor(objectTypeMaker); + this.typeMaker = typeMaker; + this.createParameterVisitor = new CreateParameterVisitor(typeMaker); + this.createLocalVariableVisitor = new CreateLocalVariableVisitor(typeMaker); // Initialize local black list variable names if (classFile.getFields() != null) { @@ -61,22 +59,22 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa String descriptor = field.getDescriptor(); if (descriptor.charAt(descriptor.length() - 1) == ';') { - objectTypeMaker.makeFromDescriptor(descriptor).accept(populateBlackListNamesVisitor); + typeMaker.makeFromDescriptor(descriptor).accept(populateBlackListNamesVisitor); } blackListNames.add(field.getName()); } } - objectTypeMaker.makeFromInternalTypeName(classFile.getInternalTypeName()).accept(populateBlackListNamesVisitor); + typeMaker.makeFromInternalTypeName(classFile.getInternalTypeName()).accept(populateBlackListNamesVisitor); if (classFile.getSuperTypeName() != null) { - objectTypeMaker.makeFromInternalTypeName(classFile.getSuperTypeName()).accept(populateBlackListNamesVisitor); + typeMaker.makeFromInternalTypeName(classFile.getSuperTypeName()).accept(populateBlackListNamesVisitor); } if (classFile.getInterfaceTypeNames() != null) { for (String interfaceTypeName : classFile.getInterfaceTypeNames()) { - objectTypeMaker.makeFromInternalTypeName(interfaceTypeName).accept(populateBlackListNamesVisitor); + typeMaker.makeFromInternalTypeName(interfaceTypeName).accept(populateBlackListNamesVisitor); } } @@ -95,7 +93,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa if ((method.getAccessFlags() & FLAG_STATIC) == 0) { if (localVariableSet.root(0) == null) { // Local variable missing - localVariableSet.add(0, new ObjectLocalVariable(objectTypeMaker, 0, 0, objectTypeMaker.makeFromInternalTypeName(classFile.getInternalTypeName()), "this")); + localVariableSet.add(0, new ObjectLocalVariable(typeMaker, 0, 0, typeMaker.makeFromInternalTypeName(classFile.getInternalTypeName()), "this")); blackListNames.add("this"); } firstVariableIndex = 1; @@ -105,7 +103,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa if ((classFile.getAccessFlags() & FLAG_ENUM) != 0) { if (localVariableSet.root(1) == null) { // Local variable missing - localVariableSet.add(1, new ObjectLocalVariable(objectTypeMaker, 1, 0, ObjectType.TYPE_STRING, "this$enum$name")); + localVariableSet.add(1, new ObjectLocalVariable(typeMaker, 1, 0, ObjectType.TYPE_STRING, "this$enum$name")); blackListNames.add("this$enum$name"); } if (localVariableSet.root(2) == null) { @@ -116,7 +114,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa } else if ((classFile.getOuterClassFile() != null) && ((classFile.getAccessFlags() & FLAG_STATIC) == 0)) { if (localVariableSet.root(1) == null) { // Local variable missing - localVariableSet.add(1, new ObjectLocalVariable(objectTypeMaker, 1, 0, objectTypeMaker.makeFromInternalTypeName(classFile.getOuterClassFile().getInternalTypeName()), "this$0")); + localVariableSet.add(1, new ObjectLocalVariable(typeMaker, 1, 0, typeMaker.makeFromInternalTypeName(classFile.getOuterClassFile().getInternalTypeName()), "this$0")); blackListNames.add("this$0"); } } @@ -147,7 +145,7 @@ public LocalVariableMaker(ObjectTypeMaker objectTypeMaker, SignatureParser signa } else { Annotations[] visiblesArray = (rvpa == null) ? null : rvpa.getParameterAnnotations(); Annotations[] invisiblesArray = (ripa == null) ? null : ripa.getParameterAnnotations(); - AnnotationConverter annotationConverter = new AnnotationConverter(objectTypeMaker); + AnnotationConverter annotationConverter = new AnnotationConverter(typeMaker); for (int parameterIndex=0, variableIndex=firstVariableIndex; parameterIndex<=lastParameterIndex; parameterIndex++, variableIndex++) { AbstractLocalVariable lv = localVariableSet.root(variableIndex); @@ -187,14 +185,14 @@ protected void initLocalVariablesFromAttributes(Method method) { AbstractLocalVariable lv; if (descriptor.charAt(descriptor.length() - 1) == ';') { - lv = new ObjectLocalVariable(objectTypeMaker, index, startPc, objectTypeMaker.makeFromDescriptor(descriptor), name); + lv = new ObjectLocalVariable(typeMaker, index, startPc, typeMaker.makeFromDescriptor(descriptor), name); } else { - int dimension = SignatureParser.countDimension(descriptor); + int dimension = TypeMaker.countDimension(descriptor); if (dimension == 0) { lv = new PrimitiveLocalVariable(index, startPc, PrimitiveType.getPrimitiveType(descriptor.charAt(0)), name); } else { - lv = new ObjectLocalVariable(objectTypeMaker, index, startPc, signatureParser.parseTypeSignature(descriptor.substring(dimension)).createType(dimension), name); + lv = new ObjectLocalVariable(typeMaker, index, startPc, typeMaker.parseTypeSignature(descriptor.substring(dimension)).createType(dimension), name); } } @@ -211,7 +209,7 @@ protected void initLocalVariablesFromAttributes(Method method) { for (LocalVariableType lv : localVariableTypeTable.getLocalVariableTypeTable()) { updateTypeVisitor.setLocalVariableType(lv); - signatureParser.parseTypeSignature(lv.getSignature()).accept(updateTypeVisitor); + typeMaker.parseTypeSignature(lv.getSignature()).accept(updateTypeVisitor); } } } @@ -229,7 +227,7 @@ protected void initLocalVariablesFromParameterTypes(ClassFile classFile, List OBJECT_TYPE_CACHE = new HashMap<>(); - protected static final HashMap OBJECT_PRIMITIVE_TYPE_CACHE = new HashMap<>(); - - static { - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_CLASS.getInternalName(), ObjectType.TYPE_CLASS); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_OBJECT.getInternalName(), ObjectType.TYPE_OBJECT); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_STRING.getInternalName(), ObjectType.TYPE_STRING); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_THROWABLE.getInternalName(), ObjectType.TYPE_THROWABLE); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_EXCEPTION.getInternalName(), ObjectType.TYPE_EXCEPTION); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_RUNTIME_EXCEPTION.getInternalName(), ObjectType.TYPE_RUNTIME_EXCEPTION); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_SYSTEM.getInternalName(), ObjectType.TYPE_SYSTEM); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_STRING_BUILDER.getInternalName(), ObjectType.TYPE_STRING_BUILDER); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_STRING_BUFFER.getInternalName(), ObjectType.TYPE_STRING_BUFFER); - OBJECT_TYPE_CACHE.put(ObjectType.TYPE_THREAD.getInternalName(), ObjectType.TYPE_THREAD); - - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_BOOLEAN.getInternalName(), ObjectType.TYPE_PRIMITIVE_BOOLEAN); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_BYTE.getInternalName(), ObjectType.TYPE_PRIMITIVE_BYTE); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_CHAR.getInternalName(), ObjectType.TYPE_PRIMITIVE_CHAR); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_DOUBLE.getInternalName(), ObjectType.TYPE_PRIMITIVE_DOUBLE); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_FLOAT.getInternalName(), ObjectType.TYPE_PRIMITIVE_FLOAT); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_INT.getInternalName(), ObjectType.TYPE_PRIMITIVE_INT); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_LONG.getInternalName(), ObjectType.TYPE_PRIMITIVE_LONG); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_SHORT.getInternalName(), ObjectType.TYPE_PRIMITIVE_SHORT); - OBJECT_PRIMITIVE_TYPE_CACHE.put(ObjectType.TYPE_PRIMITIVE_VOID.getInternalName(), ObjectType.TYPE_PRIMITIVE_VOID); - } - - protected HashMap descriptorToObjectTypeCache = new HashMap<>(1024); - protected HashMap internalTypeNameToObjectTypeCache = new HashMap<>(1024); - protected HashMap hierarchy = new HashMap<>(1024); - protected Loader loader; - - public ObjectTypeMaker(Loader loader) { - this.loader = loader; - } - - public ObjectType makeFromDescriptor(String descriptor) { - ObjectType ot = descriptorToObjectTypeCache.get(descriptor); - - if (ot == null) { - if (descriptor.charAt(0) == '[') { - int dimension = 1; - - while (descriptor.charAt(dimension) == '[') { - dimension++; - } - - ot = (ObjectType)makeFromDescriptorWithoutBracket(descriptor.substring(dimension)).createType(dimension); - } else { - ot = makeFromDescriptorWithoutBracket(descriptor); - } - - descriptorToObjectTypeCache.put(descriptor, ot); - } - - return ot; - } - - private ObjectType makeFromDescriptorWithoutBracket(String descriptor) { - ObjectType ot = OBJECT_PRIMITIVE_TYPE_CACHE.get(descriptor); - - if (ot == null) { - ot = makeFromInternalTypeName(descriptor.substring(1, descriptor.length()-1)); - } - - return ot; - } - - public ObjectType makeFromInternalTypeName(String internalTypeName) { - assert (internalTypeName != null) && !internalTypeName.endsWith(";") : "ObjectTypeMaker.makeFromInternalTypeName(internalTypeName) : invalid internalTypeName"; - - ObjectType ot = OBJECT_TYPE_CACHE.get(internalTypeName); - - if (ot == null) { - ot = internalTypeNameToObjectTypeCache.get(internalTypeName); - } - - if (ot == null) { - // Search class file with loader, first - ot = loadFromLoader(internalTypeName); - - if (ot == null) { - // File not found with the loader -> Try to load class with system class loader - ot = loadFromClassLoader(internalTypeName); - } - - if (ot == null) { - // File not found with the system class loader -> Create type just from 'internalTypeName' - ot = create(internalTypeName); - } - } - - return ot; - } - - public ObjectType makeFromDescriptorOrInternalTypeName(String descriptorOrInternalTypeName) { - return (descriptorOrInternalTypeName.charAt(0) == '[') ? makeFromDescriptor(descriptorOrInternalTypeName) : makeFromInternalTypeName(descriptorOrInternalTypeName); - } - - private ObjectType loadFromLoader(String internalTypeName) { - try { - ObjectType ot = internalTypeNameToObjectTypeCache.get(internalTypeName); - - if ((ot == null) && loader.canLoad(internalTypeName)) { - String outerTypeName = getOuterTypeName(internalTypeName); - - if (outerTypeName == null) { - int lastSlash = internalTypeName.lastIndexOf('/'); - String qualifiedName = internalTypeName.replace('/', '.'); - String name = qualifiedName.substring(lastSlash + 1); - - ot = new ObjectType(internalTypeName, qualifiedName, name); - } else { - ObjectType outerOT = loadFromLoader(outerTypeName); - int index; - - assert outerOT != null; - - if (internalTypeName.length() > outerTypeName.length() + 1) { - index = outerTypeName.length(); - } else { - index = internalTypeName.lastIndexOf('$'); - } - - String innerName = internalTypeName.substring(index + 1); - - if (Character.isDigit(innerName.charAt(0))) { - ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerOT); - } else { - String qualifiedName = outerOT.getQualifiedName() + '.' + innerName; - ot = new InnerObjectType(internalTypeName, qualifiedName, innerName, outerOT); - } - } - - internalTypeNameToObjectTypeCache.put(internalTypeName, ot); - } - - return ot; - } catch (Exception ignore) { - // Class file not found by the system class loader, or invalid class file - return null; - } - } - - private ObjectType loadFromClassLoader(String internalTypeName) { - ObjectType ot = internalTypeNameToObjectTypeCache.get(internalTypeName); - - if (ot == null) { - try { - Class clazz = getClass().getClassLoader().loadClass(internalTypeName.replace('/', '.')); - String qualifiedName = clazz.getCanonicalName(); - String name = clazz.getSimpleName(); - - if (clazz.isMemberClass()) { - String outerInternalTypeName; - - if (name.isEmpty()) { - // Anonymous type - outerInternalTypeName = internalTypeName.substring(0, internalTypeName.lastIndexOf('$')); - } else { - // Inner type - outerInternalTypeName = internalTypeName.substring(0, internalTypeName.length()-name.length()-1); - } - - ObjectType outerSot = loadFromClassLoader(outerInternalTypeName); - - ot = new InnerObjectType(internalTypeName, qualifiedName, name, outerSot); - } else { - ot = new ObjectType(internalTypeName, qualifiedName, name); - } - } catch (ClassNotFoundException ignore) { - } - - internalTypeNameToObjectTypeCache.put(internalTypeName, ot); - } - - return ot; - } - - private ObjectType create(String internalTypeName) { - int lastSlash = internalTypeName.lastIndexOf('/'); - int lastDollar = internalTypeName.lastIndexOf('$'); - ObjectType ot; - - if (lastSlash < lastDollar) { - String outerTypeName = internalTypeName.substring(0, lastDollar); - ObjectType outerSot = create(outerTypeName); - String innerName = internalTypeName.substring(outerTypeName.length() + 1); - - if (innerName.isEmpty()) { - String qualifiedName = internalTypeName.replace('/', '.'); - String name = qualifiedName.substring(lastSlash + 1); - ot = new ObjectType(internalTypeName, qualifiedName, name); - } else if (Character.isDigit(innerName.charAt(0))) { - ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerSot); - } else { - String qualifiedName = outerSot.getQualifiedName() + '.' + innerName; - ot = new InnerObjectType(internalTypeName, qualifiedName, innerName, outerSot); - } - } else { - String qualifiedName = internalTypeName.replace('/', '.'); - String name = qualifiedName.substring(lastSlash + 1); - ot = new ObjectType(internalTypeName, qualifiedName, name); - } - - internalTypeNameToObjectTypeCache.put(internalTypeName, ot); - - return ot; - } - - public boolean isAssignable(ObjectType parent, ObjectType child) { - if (parent == TYPE_UNDEFINED_OBJECT) { - return true; - } else if (parent.getDimension() > 0) { - return (parent.getDimension() == child.getDimension()) && parent.getInternalName().equals(child.getInternalName()); - } else { - String parentInternalName = parent.getInternalName(); - String childInternalName = child.getInternalName(); - - if (parentInternalName.equals(childInternalName) || parentInternalName.equals("java/lang/Object")) - return true; - - return recursiveIsAssignable(parentInternalName, childInternalName); - } - } - - @SuppressWarnings("unchecked") - private boolean recursiveIsAssignable(String parentInternalName, String childInternalName) { - if (childInternalName.equals("java/lang/Object")) - return false; - - String[] superClassAndInterfaceNames = hierarchy.get(childInternalName); - - if (superClassAndInterfaceNames == null) { - try { - if (loader.canLoad(childInternalName)) { - loadFromLoader(childInternalName); - superClassAndInterfaceNames = hierarchy.get(childInternalName); - } else { - Class childClazz = getClass().getClassLoader().loadClass(childInternalName.replace('/', '.')); - Class parentClazz = getClass().getClassLoader().loadClass(parentInternalName.replace('/', '.')); - return parentClazz.isAssignableFrom(childClazz); - } - } catch (Exception ignore) { - return false; - } - } - - if (superClassAndInterfaceNames != null) { - for (String name : superClassAndInterfaceNames) { - if (parentInternalName.equals(name)) - return true; - } - - for (String name : superClassAndInterfaceNames) { - if (recursiveIsAssignable(parentInternalName, name)) - return true; - } - } - - return false; - } - - private String getOuterTypeName(String internalTypeName) throws Exception { - return loadTypeAndApplyFunction(internalTypeName, null, searchOuterTypeName); - } - - private Object[] constants = new Object[1000]; - - @FunctionalInterface - private interface Function { - String apply(ClassFileReader reader, String typeName, String innerTypeName) throws Exception; - } - - private Function checkInnerTypeName = (reader, typeName, innerTypeName) -> { - int count = reader.readUnsignedShort(); - - for(int i=0; i < count; i++) { - int innerTypeIndex = reader.readUnsignedShort(); - - // Skip 'outerTypeIndex', 'innerNameIndex' & innerAccessFlags' - reader.skip(3 * 2); - - ConstantClass cc = (ConstantClass)constants[innerTypeIndex]; - String innerInternalTypeName = (String)constants[cc.getNameIndex()]; - - if (innerTypeName.equals(innerInternalTypeName)) { - return typeName; - } - } - - return null; - }; - - private Function searchOuterTypeName = (reader, typeName, innerTypeName) -> { - int count = reader.readUnsignedShort(); - - for(int i=0; i < count; i++) { - int innerTypeIndex = reader.readUnsignedShort(); - int outerTypeIndex = reader.readUnsignedShort(); - - // Skip 'innerNameIndex' & innerAccessFlags' - reader.skip(2 * 2); - - ConstantClass cc = (ConstantClass)constants[innerTypeIndex]; - innerTypeName = (String)constants[cc.getNameIndex()]; - - if (innerTypeName.equals(typeName)) { - if (outerTypeIndex == 0) { - // Synthetic inner class -> Search outer class - int lastDollar = typeName.lastIndexOf('$'); - - if (lastDollar != -1) { - String outerTypeName = typeName.substring(0, lastDollar); - return loadTypeAndApplyFunction(outerTypeName, typeName, checkInnerTypeName); - } - - return null; - } else { - // Return 'outerTypeName' - cc = (ConstantClass)constants[outerTypeIndex]; - return (String)constants[cc.getNameIndex()]; - } - } - } - - return null; - }; - - private String loadTypeAndApplyFunction(String typeName, String innerTypeName, Function function) throws Exception { - byte[] data = loader.load(typeName); - - if (data == null) { - return null; - } else { - ClassFileReader reader = new ClassFileReader(data); - - int magic = reader.readInt(); - - if (magic != ClassFileReader.JAVA_MAGIC_NUMBER) - throw new ClassFileFormatException("Invalid CLASS file"); - - // Skip 'minorVersion', 'majorVersion' - reader.skip(2 * 2); - - Object[] constants = loadConstants(reader); - - // Skip 'accessFlags' & 'thisClassIndex' - reader.skip(2 * 2); - - // Load super class name - int superClassIndex = reader.readUnsignedShort(); - String superClassName; - - if (superClassIndex == 0) { - superClassName = null; - } else { - ConstantClass cc = (ConstantClass)constants[superClassIndex]; - superClassName = (String)constants[cc.getNameIndex()]; - } - - // Load interface blackListNames - int count = reader.readUnsignedShort(); - String[] superClassAndInterfaceNames = new String[count + 1]; - - superClassAndInterfaceNames[0] = superClassName; - - for (int i = 1; i <= count; i++) { - int interfaceIndex = reader.readUnsignedShort(); - ConstantClass cc = (ConstantClass)constants[interfaceIndex]; - superClassAndInterfaceNames[i] = (String)constants[cc.getNameIndex()]; - } - - hierarchy.put(typeName, superClassAndInterfaceNames); - - // Skip fields - count = reader.readUnsignedShort(); - for (int i = 0; i < count; i++) { - // skip 'accessFlags', 'nameIndex', 'signatureIndex' - reader.skip(3 * 2); - skipAttributes(reader); - } - - // Skip methods - count = reader.readUnsignedShort(); - for (int i = 0; i < count; i++) { - // skip 'accessFlags', 'nameIndex', 'signatureIndex' - reader.skip(3 * 2); - skipAttributes(reader); - } - - // Load attributes - count = reader.readUnsignedShort(); - for (int i = 0; i < count; i++) { - int attributeNameIndex = reader.readUnsignedShort(); - int attributeLength = reader.readInt(); - - String name = (String)constants[attributeNameIndex]; - - if ("InnerClasses".equals(name)) { - return function.apply(reader, typeName, innerTypeName); - } else { - reader.skip(attributeLength); - } - } - - return null; - } - } - - private Object[] loadConstants(ClassFileReader reader) throws Exception { - int count = reader.readUnsignedShort(); - - if (count == 0) - return null; - - if (constants.length < count) { - constants = new Object[count]; - } - - for (int i=1; igetAttribute("Code").getCode(); @@ -475,7 +475,7 @@ protected void parseTry(WatchDog watchdog, BasicBlock basicBlock, Statements sta if (exceptionHandler.getOtherInternalThrowableNames() != null) { for (String name : exceptionHandler.getOtherInternalThrowableNames()) { - cc.addType(objectTypeMaker.makeFromInternalTypeName(name)); + cc.addType(typeMaker.makeFromInternalTypeName(name)); } } @@ -898,7 +898,7 @@ protected Expression createObjectTypeReferenceDotClassExpression(int lineNumber, } String typeName = ((StringConstantExpression) mie.getParameters()).getString(); - ObjectType ot = objectTypeMaker.makeFromInternalTypeName(typeName.replace('.', '/')); + ObjectType ot = typeMaker.makeFromInternalTypeName(typeName.replace('.', '/')); return new TypeReferenceDotClassExpression(lineNumber, ot); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java similarity index 53% rename from src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java rename to src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index 9e1cde34..7699aac9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SignatureParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -7,16 +7,22 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; +import org.jd.core.v1.api.loader.Loader; import org.jd.core.v1.model.classfile.ClassFile; import org.jd.core.v1.model.classfile.Field; import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.model.classfile.attribute.AttributeExceptions; import org.jd.core.v1.model.classfile.attribute.AttributeSignature; +import org.jd.core.v1.model.classfile.constant.ConstantClass; import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.deserializer.classfile.ClassFileFormatException; +import org.jd.core.v1.service.deserializer.classfile.ClassFileReader; import org.jd.core.v1.util.DefaultList; import java.util.HashMap; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; + /* * https://jcp.org/aboutJava/communityprocess/maintenance/jsr924/JVMS-SE5.0-Ch4-ClassFile.pdf * @@ -24,25 +30,24 @@ * * http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html */ -public class SignatureParser { - protected HashMap methodTypesCache = new HashMap<>(1024); - protected HashMap typeCache = new HashMap<>(1024); - protected ObjectTypeMaker objectTypeMaker; - - public SignatureParser(ObjectTypeMaker objectTypeMaker) { - this.objectTypeMaker = objectTypeMaker; - - typeCache.put("B", PrimitiveType.TYPE_BYTE); - typeCache.put("C", PrimitiveType.TYPE_CHAR); - typeCache.put("D", PrimitiveType.TYPE_DOUBLE); - typeCache.put("F", PrimitiveType.TYPE_FLOAT); - typeCache.put("I", PrimitiveType.TYPE_INT); - typeCache.put("J", PrimitiveType.TYPE_LONG); - typeCache.put("S", PrimitiveType.TYPE_SHORT); - typeCache.put("Z", PrimitiveType.TYPE_BOOLEAN); - typeCache.put("java/lang/Class", ObjectType.TYPE_CLASS); - typeCache.put("java/lang/Object", ObjectType.TYPE_OBJECT); - typeCache.put("java/lang/String", ObjectType.TYPE_STRING); +public class TypeMaker { + protected HashMap signatureToMethodTypes = new HashMap<>(1024); + protected HashMap signatureToType = new HashMap<>(1024); + + public TypeMaker(Loader loader) { + this.loader = loader; + + signatureToType.put("B", PrimitiveType.TYPE_BYTE); + signatureToType.put("C", PrimitiveType.TYPE_CHAR); + signatureToType.put("D", PrimitiveType.TYPE_DOUBLE); + signatureToType.put("F", PrimitiveType.TYPE_FLOAT); + signatureToType.put("I", PrimitiveType.TYPE_INT); + signatureToType.put("J", PrimitiveType.TYPE_LONG); + signatureToType.put("S", PrimitiveType.TYPE_SHORT); + signatureToType.put("Z", PrimitiveType.TYPE_BOOLEAN); + signatureToType.put("java/lang/Class", ObjectType.TYPE_CLASS); + signatureToType.put("java/lang/Object", ObjectType.TYPE_OBJECT); + signatureToType.put("java/lang/String", ObjectType.TYPE_STRING); } /** @@ -56,7 +61,7 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { TypeTypes typeTypes = new TypeTypes(); String internalTypeName = classFile.getInternalTypeName(); - typeTypes.thisType = objectTypeMaker.makeFromInternalTypeName(internalTypeName); + typeTypes.thisType = makeFromInternalTypeName(internalTypeName); AttributeSignature attributeSignature = classFile.getAttribute("Signature"); @@ -66,18 +71,18 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { String[] interfaceTypeNames = classFile.getInterfaceTypeNames(); if (! "java/lang/Object".equals(superTypeName)) { - typeTypes.superType = objectTypeMaker.makeFromInternalTypeName(superTypeName); + typeTypes.superType = makeFromInternalTypeName(superTypeName); } if (interfaceTypeNames != null) { int length = interfaceTypeNames.length; if (length == 1) { - typeTypes.interfaces = objectTypeMaker.makeFromInternalTypeName(interfaceTypeNames[0]); + typeTypes.interfaces = makeFromInternalTypeName(interfaceTypeNames[0]); } else { Types list = new Types(length); for (String interfaceTypeName : interfaceTypeNames) { - list.add(objectTypeMaker.makeFromInternalTypeName(interfaceTypeName)); + list.add(makeFromInternalTypeName(interfaceTypeName)); } typeTypes.interfaces = list; } @@ -120,25 +125,25 @@ public MethodTypes parseConstructorSignature(Method method) { if (attributeSignature == null) { return parseMethodSignature(method.getDescriptor(), method); } else { - // Signature does not contain synthetic parameters like outer type name, for example. + // Signature does not contain synthetic parameterTypes like outer type name, for example. MethodTypes mt1 = parseMethodSignature(attributeSignature.getSignature(), method); MethodTypes mt2 = parseMethodSignature(method.getDescriptor(), method); - if (mt1.parameters.size() == mt2.parameters.size()) { + if (mt1.parameterTypes.size() == mt2.parameterTypes.size()) { return mt1; - } else if (mt1.parameters.isEmpty() && (mt1.typeParameters == null)) { + } else if (mt1.parameterTypes.isEmpty() && (mt1.typeParameters == null)) { return mt2; } else { - DefaultList parameters = new DefaultList<>(mt2.parameters); + DefaultList parameters = new DefaultList<>(mt2.parameterTypes); - parameters.subList(1, 1+mt1.parameters.size()).clear(); - parameters.addAll(1, mt1.parameters); + parameters.subList(1, 1+mt1.parameterTypes.size()).clear(); + parameters.addAll(1, mt1.parameterTypes); MethodTypes mt3 = new MethodTypes(); mt3.typeParameters = mt1.typeParameters; - mt3.parameters = parameters; - mt3.returned = mt1.returned; + mt3.parameterTypes = parameters; + mt3.returnedType = mt1.returnedType; mt3.exceptions = mt1.exceptions; return mt3; @@ -159,12 +164,12 @@ public Type parseFieldSignature(Field field) { } public Type parseTypeSignature(String signature) { - Type type = typeCache.get(signature); + Type type = signatureToType.get(signature); if (type == null) { SignatureReader reader = new SignatureReader(signature); type = parseReferenceTypeSignature(reader); - typeCache.put(signature, type); + signatureToType.put(signature, type); } return type; @@ -172,12 +177,12 @@ public Type parseTypeSignature(String signature) { public DefaultList parseParameterTypes(String signature) { MethodTypes methodTypes = parseMethodSignature(signature, null); - return (methodTypes==null) ? DefaultList.emptyList() : methodTypes.parameters; + return (methodTypes==null) ? DefaultList.emptyList() : methodTypes.parameterTypes; } public Type parseReturnedType(String signature) { MethodTypes methodTypes = parseMethodSignature(signature, null); - return (methodTypes==null) ? null : methodTypes.returned; + return (methodTypes==null) ? null : methodTypes.returnedType; } public static int countDimension(String descriptor) { @@ -215,7 +220,7 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { } } - MethodTypes methodTypes = methodTypesCache.get(cacheKey); + MethodTypes methodTypes = signatureToMethodTypes.get(cacheKey); if (methodTypes == null) { SignatureReader reader = new SignatureReader(signature); @@ -231,7 +236,7 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { Type firstParameter = parseReferenceTypeSignature(reader); if (firstParameter == null) { - methodTypes.parameters = DefaultList.emptyList(); + methodTypes.parameterTypes = DefaultList.emptyList(); } else { Type nextParameter = parseReferenceTypeSignature(reader); DefaultList list = new DefaultList<>(); @@ -243,14 +248,14 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { nextParameter = parseReferenceTypeSignature(reader); } - methodTypes.parameters = list; + methodTypes.parameterTypes = list; } if (reader.read() != ')') throw new SignatureFormatException(signature); // Result - methodTypes.returned = parseReferenceTypeSignature(reader); + methodTypes.returnedType = parseReferenceTypeSignature(reader); // Exceptions Type firstException = parseExceptionSignature(reader); @@ -264,12 +269,12 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { String[] exceptionTypeNames = attributeExceptions.getExceptionTypeNames(); if (exceptionTypeNames.length == 1) { - methodTypes.exceptions = objectTypeMaker.makeFromInternalTypeName(exceptionTypeNames[0]); + methodTypes.exceptions = makeFromInternalTypeName(exceptionTypeNames[0]); } else { Types list = new Types(exceptionTypeNames.length); for (String exceptionTypeName : exceptionTypeNames) { - list.add(objectTypeMaker.makeFromInternalTypeName(exceptionTypeName)); + list.add(makeFromInternalTypeName(exceptionTypeName)); } methodTypes.exceptions = list; @@ -295,7 +300,7 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { } } - methodTypesCache.put(cacheKey, methodTypes); + signatureToMethodTypes.put(cacheKey, methodTypes); } return methodTypes; @@ -521,7 +526,7 @@ protected ObjectType parseClassTypeSignature(SignatureReader reader, int dimensi } String internalTypeName = reader.substring(index); - ObjectType ot = objectTypeMaker.makeFromInternalTypeName(internalTypeName); + ObjectType ot = makeFromInternalTypeName(internalTypeName); if (endMarker == '<') { // Skip '<' @@ -784,8 +789,467 @@ public static class TypeTypes { public static class MethodTypes { public BaseTypeParameter typeParameters; - public DefaultList parameters; - public Type returned; + public DefaultList parameterTypes; + public Type returnedType; public BaseType exceptions; } + + protected static final HashMap INTERNALNAME_TO_OBJECTTYPE = new HashMap<>(); + protected static final HashMap INTERNALNAME_TO_OBJECTPRIMITIVETYPE = new HashMap<>(); + + static { + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_CLASS.getInternalName(), ObjectType.TYPE_CLASS); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_OBJECT.getInternalName(), ObjectType.TYPE_OBJECT); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_STRING.getInternalName(), ObjectType.TYPE_STRING); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_THROWABLE.getInternalName(), ObjectType.TYPE_THROWABLE); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_EXCEPTION.getInternalName(), ObjectType.TYPE_EXCEPTION); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_RUNTIME_EXCEPTION.getInternalName(), ObjectType.TYPE_RUNTIME_EXCEPTION); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_SYSTEM.getInternalName(), ObjectType.TYPE_SYSTEM); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_STRING_BUILDER.getInternalName(), ObjectType.TYPE_STRING_BUILDER); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_STRING_BUFFER.getInternalName(), ObjectType.TYPE_STRING_BUFFER); + INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_THREAD.getInternalName(), ObjectType.TYPE_THREAD); + + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_BOOLEAN.getInternalName(), ObjectType.TYPE_PRIMITIVE_BOOLEAN); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_BYTE.getInternalName(), ObjectType.TYPE_PRIMITIVE_BYTE); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_CHAR.getInternalName(), ObjectType.TYPE_PRIMITIVE_CHAR); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_DOUBLE.getInternalName(), ObjectType.TYPE_PRIMITIVE_DOUBLE); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_FLOAT.getInternalName(), ObjectType.TYPE_PRIMITIVE_FLOAT); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_INT.getInternalName(), ObjectType.TYPE_PRIMITIVE_INT); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_LONG.getInternalName(), ObjectType.TYPE_PRIMITIVE_LONG); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_SHORT.getInternalName(), ObjectType.TYPE_PRIMITIVE_SHORT); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_VOID.getInternalName(), ObjectType.TYPE_PRIMITIVE_VOID); + } + + protected HashMap descriptorToObjectType = new HashMap<>(1024); + protected HashMap internalTypeNameToObjectType = new HashMap<>(1024); + protected HashMap hierarchy = new HashMap<>(1024); + protected Loader loader; + + public ObjectType makeFromDescriptor(String descriptor) { + ObjectType ot = descriptorToObjectType.get(descriptor); + + if (ot == null) { + if (descriptor.charAt(0) == '[') { + int dimension = 1; + + while (descriptor.charAt(dimension) == '[') { + dimension++; + } + + ot = (ObjectType)makeFromDescriptorWithoutBracket(descriptor.substring(dimension)).createType(dimension); + } else { + ot = makeFromDescriptorWithoutBracket(descriptor); + } + + descriptorToObjectType.put(descriptor, ot); + } + + return ot; + } + + private ObjectType makeFromDescriptorWithoutBracket(String descriptor) { + ObjectType ot = INTERNALNAME_TO_OBJECTPRIMITIVETYPE.get(descriptor); + + if (ot == null) { + ot = makeFromInternalTypeName(descriptor.substring(1, descriptor.length()-1)); + } + + return ot; + } + + public ObjectType makeFromInternalTypeName(String internalTypeName) { + assert (internalTypeName != null) && !internalTypeName.endsWith(";") : "ObjectTypeMaker.makeFromInternalTypeName(internalTypeName) : invalid internalTypeName"; + + ObjectType ot = INTERNALNAME_TO_OBJECTTYPE.get(internalTypeName); + + if (ot == null) { + ot = internalTypeNameToObjectType.get(internalTypeName); + } + + if (ot == null) { + // Search class file with loader, first + ot = loadFromLoader(internalTypeName); + + if (ot == null) { + // File not found with the loader -> Try to load class with system class loader + ot = loadFromClassLoader(internalTypeName); + } + + if (ot == null) { + // File not found with the system class loader -> Create type just from 'internalTypeName' + ot = create(internalTypeName); + } + } + + return ot; + } + + public ObjectType makeFromDescriptorOrInternalTypeName(String descriptorOrInternalTypeName) { + return (descriptorOrInternalTypeName.charAt(0) == '[') ? makeFromDescriptor(descriptorOrInternalTypeName) : makeFromInternalTypeName(descriptorOrInternalTypeName); + } + + private ObjectType loadFromLoader(String internalTypeName) { + try { + ObjectType ot = internalTypeNameToObjectType.get(internalTypeName); + + if ((ot == null) && loader.canLoad(internalTypeName)) { + String outerTypeName = getOuterTypeName(internalTypeName); + + if (outerTypeName == null) { + int lastSlash = internalTypeName.lastIndexOf('/'); + String qualifiedName = internalTypeName.replace('/', '.'); + String name = qualifiedName.substring(lastSlash + 1); + + ot = new ObjectType(internalTypeName, qualifiedName, name); + } else { + ObjectType outerOT = loadFromLoader(outerTypeName); + int index; + + assert outerOT != null; + + if (internalTypeName.length() > outerTypeName.length() + 1) { + index = outerTypeName.length(); + } else { + index = internalTypeName.lastIndexOf('$'); + } + + String innerName = internalTypeName.substring(index + 1); + + if (Character.isDigit(innerName.charAt(0))) { + ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerOT); + } else { + String qualifiedName = outerOT.getQualifiedName() + '.' + innerName; + ot = new InnerObjectType(internalTypeName, qualifiedName, innerName, outerOT); + } + } + + internalTypeNameToObjectType.put(internalTypeName, ot); + } + + return ot; + } catch (Exception ignore) { + // Class file not found by the system class loader, or invalid class file + return null; + } + } + + private ObjectType loadFromClassLoader(String internalTypeName) { + ObjectType ot = internalTypeNameToObjectType.get(internalTypeName); + + if (ot == null) { + try { + Class clazz = getClass().getClassLoader().loadClass(internalTypeName.replace('/', '.')); + String qualifiedName = clazz.getCanonicalName(); + String name = clazz.getSimpleName(); + + if (clazz.isMemberClass()) { + String outerInternalTypeName; + + if (name.isEmpty()) { + // Anonymous type + outerInternalTypeName = internalTypeName.substring(0, internalTypeName.lastIndexOf('$')); + } else { + // Inner type + outerInternalTypeName = internalTypeName.substring(0, internalTypeName.length()-name.length()-1); + } + + ObjectType outerSot = loadFromClassLoader(outerInternalTypeName); + + ot = new InnerObjectType(internalTypeName, qualifiedName, name, outerSot); + } else { + ot = new ObjectType(internalTypeName, qualifiedName, name); + } + } catch (ClassNotFoundException ignore) { + } + + internalTypeNameToObjectType.put(internalTypeName, ot); + } + + return ot; + } + + private ObjectType create(String internalTypeName) { + int lastSlash = internalTypeName.lastIndexOf('/'); + int lastDollar = internalTypeName.lastIndexOf('$'); + ObjectType ot; + + if (lastSlash < lastDollar) { + String outerTypeName = internalTypeName.substring(0, lastDollar); + ObjectType outerSot = create(outerTypeName); + String innerName = internalTypeName.substring(outerTypeName.length() + 1); + + if (innerName.isEmpty()) { + String qualifiedName = internalTypeName.replace('/', '.'); + String name = qualifiedName.substring(lastSlash + 1); + ot = new ObjectType(internalTypeName, qualifiedName, name); + } else if (Character.isDigit(innerName.charAt(0))) { + ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerSot); + } else { + String qualifiedName = outerSot.getQualifiedName() + '.' + innerName; + ot = new InnerObjectType(internalTypeName, qualifiedName, innerName, outerSot); + } + } else { + String qualifiedName = internalTypeName.replace('/', '.'); + String name = qualifiedName.substring(lastSlash + 1); + ot = new ObjectType(internalTypeName, qualifiedName, name); + } + + internalTypeNameToObjectType.put(internalTypeName, ot); + + return ot; + } + + public boolean isAssignable(ObjectType parent, ObjectType child) { + if (parent == TYPE_UNDEFINED_OBJECT) { + return true; + } else if (parent.getDimension() > 0) { + return (parent.getDimension() == child.getDimension()) && parent.getInternalName().equals(child.getInternalName()); + } else { + String parentInternalName = parent.getInternalName(); + String childInternalName = child.getInternalName(); + + if (parentInternalName.equals(childInternalName) || parentInternalName.equals("java/lang/Object")) + return true; + + return recursiveIsAssignable(parentInternalName, childInternalName); + } + } + + @SuppressWarnings("unchecked") + private boolean recursiveIsAssignable(String parentInternalName, String childInternalName) { + if (childInternalName.equals("java/lang/Object")) + return false; + + String[] superClassAndInterfaceNames = hierarchy.get(childInternalName); + + if (superClassAndInterfaceNames == null) { + try { + if (loader.canLoad(childInternalName)) { + loadFromLoader(childInternalName); + superClassAndInterfaceNames = hierarchy.get(childInternalName); + } else { + Class childClazz = getClass().getClassLoader().loadClass(childInternalName.replace('/', '.')); + Class parentClazz = getClass().getClassLoader().loadClass(parentInternalName.replace('/', '.')); + return parentClazz.isAssignableFrom(childClazz); + } + } catch (Exception ignore) { + return false; + } + } + + if (superClassAndInterfaceNames != null) { + for (String name : superClassAndInterfaceNames) { + if (parentInternalName.equals(name)) + return true; + } + + for (String name : superClassAndInterfaceNames) { + if (recursiveIsAssignable(parentInternalName, name)) + return true; + } + } + + return false; + } + + private String getOuterTypeName(String internalTypeName) throws Exception { + return loadTypeAndApplyFunction(internalTypeName, null, searchOuterTypeName); + } + + private Object[] constants = new Object[1000]; + + @FunctionalInterface + private interface Function { + String apply(ClassFileReader reader, String typeName, String innerTypeName) throws Exception; + } + + private Function checkInnerTypeName = (reader, typeName, innerTypeName) -> { + int count = reader.readUnsignedShort(); + + for(int i=0; i < count; i++) { + int innerTypeIndex = reader.readUnsignedShort(); + + // Skip 'outerTypeIndex', 'innerNameIndex' & innerAccessFlags' + reader.skip(3 * 2); + + ConstantClass cc = (ConstantClass)constants[innerTypeIndex]; + String innerInternalTypeName = (String)constants[cc.getNameIndex()]; + + if (innerTypeName.equals(innerInternalTypeName)) { + return typeName; + } + } + + return null; + }; + + private Function searchOuterTypeName = (reader, typeName, innerTypeName) -> { + int count = reader.readUnsignedShort(); + + for(int i=0; i < count; i++) { + int innerTypeIndex = reader.readUnsignedShort(); + int outerTypeIndex = reader.readUnsignedShort(); + + // Skip 'innerNameIndex' & innerAccessFlags' + reader.skip(2 * 2); + + ConstantClass cc = (ConstantClass)constants[innerTypeIndex]; + innerTypeName = (String)constants[cc.getNameIndex()]; + + if (innerTypeName.equals(typeName)) { + if (outerTypeIndex == 0) { + // Synthetic inner class -> Search outer class + int lastDollar = typeName.lastIndexOf('$'); + + if (lastDollar != -1) { + String outerTypeName = typeName.substring(0, lastDollar); + return loadTypeAndApplyFunction(outerTypeName, typeName, checkInnerTypeName); + } + + return null; + } else { + // Return 'outerTypeName' + cc = (ConstantClass)constants[outerTypeIndex]; + return (String)constants[cc.getNameIndex()]; + } + } + } + + return null; + }; + + private String loadTypeAndApplyFunction(String typeName, String innerTypeName, Function function) throws Exception { + byte[] data = loader.load(typeName); + + if (data == null) { + return null; + } else { + ClassFileReader reader = new ClassFileReader(data); + + int magic = reader.readInt(); + + if (magic != ClassFileReader.JAVA_MAGIC_NUMBER) + throw new ClassFileFormatException("Invalid CLASS file"); + + // Skip 'minorVersion', 'majorVersion' + reader.skip(2 * 2); + + Object[] constants = loadConstants(reader); + + // Skip 'accessFlags' & 'thisClassIndex' + reader.skip(2 * 2); + + // Load super class name + int superClassIndex = reader.readUnsignedShort(); + String superClassName; + + if (superClassIndex == 0) { + superClassName = null; + } else { + ConstantClass cc = (ConstantClass)constants[superClassIndex]; + superClassName = (String)constants[cc.getNameIndex()]; + } + + // Load interface blackListNames + int count = reader.readUnsignedShort(); + String[] superClassAndInterfaceNames = new String[count + 1]; + + superClassAndInterfaceNames[0] = superClassName; + + for (int i = 1; i <= count; i++) { + int interfaceIndex = reader.readUnsignedShort(); + ConstantClass cc = (ConstantClass)constants[interfaceIndex]; + superClassAndInterfaceNames[i] = (String)constants[cc.getNameIndex()]; + } + + hierarchy.put(typeName, superClassAndInterfaceNames); + + // Skip fields + count = reader.readUnsignedShort(); + for (int i = 0; i < count; i++) { + // skip 'accessFlags', 'nameIndex', 'signatureIndex' + reader.skip(3 * 2); + skipAttributes(reader); + } + + // Skip methods + count = reader.readUnsignedShort(); + for (int i = 0; i < count; i++) { + // skip 'accessFlags', 'nameIndex', 'signatureIndex' + reader.skip(3 * 2); + skipAttributes(reader); + } + + // Load attributes + count = reader.readUnsignedShort(); + for (int i = 0; i < count; i++) { + int attributeNameIndex = reader.readUnsignedShort(); + int attributeLength = reader.readInt(); + + String name = (String)constants[attributeNameIndex]; + + if ("InnerClasses".equals(name)) { + return function.apply(reader, typeName, innerTypeName); + } else { + reader.skip(attributeLength); + } + } + + return null; + } + } + + private Object[] loadConstants(ClassFileReader reader) throws Exception { + int count = reader.readUnsignedShort(); + + if (count == 0) + return null; + + if (constants.length < count) { + constants = new Object[count]; + } + + for (int i=1; i synthetic method + // Synthetic type in parameterTypes -> synthetic method method.setFlags(method.getFlags() | FLAG_SYNTHETIC); method.accept(this); break; @@ -81,7 +78,7 @@ public void visit(FieldDeclaration declaration) {} @Override public void visit(ConstructorDeclaration declaration) { ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, true, comdwln.getParameterTypes()); + LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comdwln, true, comdwln.getParameterTypes()); createParametersVariablesAndStatements(comdwln, localVariableMaker); } @@ -89,7 +86,7 @@ public void visit(ConstructorDeclaration declaration) { @Override public void visit(MethodDeclaration declaration) { ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, false, comdwln.getParameterTypes()); + LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comdwln, false, comdwln.getParameterTypes()); createParametersVariablesAndStatements(comdwln, localVariableMaker); } @@ -97,7 +94,7 @@ public void visit(MethodDeclaration declaration) { @Override public void visit(StaticInitializerDeclaration declaration) { ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(objectTypeMaker, signatureParser, comdwln, false, null); + LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comdwln, false, null); createParametersVariablesAndStatements(comdwln, localVariableMaker); } @@ -107,7 +104,7 @@ protected void createParametersVariablesAndStatements(ClassFileConstructorOrMeth ClassFileBodyDeclaration bodyDeclaration = comdwln.getBodyDeclaration(); Method method = comdwln.getMethod(); Type returnedType = comdwln.getReturnedType(); - StatementMaker statementMaker = new StatementMaker(objectTypeMaker, signatureParser, localVariableMaker, classFile, bodyDeclaration, returnedType); + StatementMaker statementMaker = new StatementMaker(typeMaker, localVariableMaker, classFile, bodyDeclaration, returnedType); try { ControlFlowGraph cfg = ControlFlowGraphMaker.make(method); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java index a2b499e8..b5b570e4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java @@ -9,17 +9,17 @@ import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.*; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; public class CreateLocalVariableVisitor extends AbstractNopTypeVisitor implements LocalVariableVisitor { - protected ObjectTypeMaker objectTypeMaker; + protected TypeMaker typeMaker; protected int index; protected int offset; protected AbstractLocalVariable localVariable; - public CreateLocalVariableVisitor(ObjectTypeMaker objectTypeMaker) { - this.objectTypeMaker = objectTypeMaker; + public CreateLocalVariableVisitor(TypeMaker typeMaker) { + this.typeMaker = typeMaker; } public void init(int index, int offset) { @@ -36,18 +36,18 @@ public void visit(PrimitiveType type) { if (type.getDimension() == 0) { localVariable = new PrimitiveLocalVariable(index, offset, type, null); } else { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null); + localVariable = new ObjectLocalVariable(typeMaker, index, offset, type, null); } } @Override public void visit(ObjectType type) { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null); + localVariable = new ObjectLocalVariable(typeMaker, index, offset, type, null); } @Override public void visit(InnerObjectType type) { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, type, null); + localVariable = new ObjectLocalVariable(typeMaker, index, offset, type, null); } @Override @@ -62,7 +62,7 @@ public void visit(GenericLocalVariable lv) { @Override public void visit(ObjectLocalVariable lv) { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, lv); + localVariable = new ObjectLocalVariable(typeMaker, index, offset, lv); } @Override @@ -70,7 +70,7 @@ public void visit(PrimitiveLocalVariable lv) { if (lv.getDimension() == 0) { localVariable = new PrimitiveLocalVariable(index, offset, lv); } else { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, offset, lv.getType(), null); + localVariable = new ObjectLocalVariable(typeMaker, index, offset, lv.getType(), null); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java index d603a48c..4042dd9b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -12,17 +12,17 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.GenericLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.ObjectLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.PrimitiveLocalVariable; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; public class CreateParameterVisitor extends AbstractNopTypeVisitor { - protected ObjectTypeMaker objectTypeMaker; + protected TypeMaker typeMaker; protected int index; protected String name; protected AbstractLocalVariable localVariable; - public CreateParameterVisitor(ObjectTypeMaker objectTypeMaker) { - this.objectTypeMaker = objectTypeMaker; + public CreateParameterVisitor(TypeMaker typeMaker) { + this.typeMaker = typeMaker; } public void init(int index, String name) { @@ -39,18 +39,18 @@ public void visit(PrimitiveType type) { if (type.getDimension() == 0) { localVariable = new PrimitiveLocalVariable(index, 0, type, name); } else { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, 0, type, name); + localVariable = new ObjectLocalVariable(typeMaker, index, 0, type, name); } } @Override public void visit(ObjectType type) { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, 0, type, name); + localVariable = new ObjectLocalVariable(typeMaker, index, 0, type, name); } @Override public void visit(InnerObjectType type) { - localVariable = new ObjectLocalVariable(objectTypeMaker, index, 0, type, name); + localVariable = new ObjectLocalVariable(typeMaker, index, 0, type, name); } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java index 002805b6..bc20fab6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -56,7 +56,7 @@ public void visit(ConstructorDeclaration declaration) { cfcd.setFlags(FLAG_SYNTHETIC); } else { FormalParameters parameters = (FormalParameters)cfcd.getFormalParameters(); - // Remove name & index parameters + // Remove name & index parameterTypes parameters.subList(0, 2).clear(); // Remove super constructor call statements.remove(0); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 6837fdfa..3695b73f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -114,7 +114,7 @@ public void visit(ConstructorDeclaration declaration) { } } - // Remove synthetic parameters + // Remove synthetic parameterTypes BaseFormalParameter parameters = cfcd.getFormalParameters(); if (parameters != null) { @@ -360,7 +360,7 @@ public void visit(NewExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - // Remove synthetic parameters + // Remove synthetic parameterTypes DefaultList outerParameterNames = cfbd.getOuterLocalVariableNames(); if (parameters.isList()) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java index 3f1be740..95c199d9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java @@ -10,16 +10,15 @@ import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; public class UpdateJavaSyntaxTreeStep1Visitor extends AbstractJavaSyntaxVisitor { protected InitInnerClassVisitor initInnerClassStep1Visitor = new InitInnerClassVisitor(); protected CreateInstructionsVisitor createInstructionsVisitor; - public UpdateJavaSyntaxTreeStep1Visitor(ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser) { - createInstructionsVisitor = new CreateInstructionsVisitor(objectTypeMaker, signatureParser); + public UpdateJavaSyntaxTreeStep1Visitor(TypeMaker typeMaker) { + createInstructionsVisitor = new CreateInstructionsVisitor(typeMaker); } @Override diff --git a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java index b268cbfd..1e92ae1e 100644 --- a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java +++ b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java @@ -14,7 +14,7 @@ import org.jd.core.v1.model.javasyntax.reference.*; import org.jd.core.v1.model.message.Message; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.AnnotationConverter; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; import org.junit.Test; @@ -27,8 +27,8 @@ public class AnnotationConverterTest extends TestCase { public void test() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - AnnotationConverter converter = new AnnotationConverter(objectTypeMaker); + TypeMaker typeMaker = new TypeMaker(loader); + AnnotationConverter converter = new AnnotationConverter(typeMaker); DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); Message message = new Message(); diff --git a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java index c91f4948..6740b6d2 100644 --- a/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java +++ b/src/test/java/org/jd/core/v1/ControlFlowGraphTest.java @@ -38,8 +38,7 @@ public class ControlFlowGraphTest extends TestCase { protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); protected ConvertClassFileProcessor converter = new ConvertClassFileProcessor(); protected ClassPathLoader loader = new ClassPathLoader(); - protected ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - protected SignatureParser signatureParser = new SignatureParser(objectTypeMaker); + protected TypeMaker typeMaker = new TypeMaker(loader); // --- Basic test ----------------------------------------------------------------------------------------------- // @Test @@ -2634,7 +2633,7 @@ protected InputStream loadFile(String zipName) throws IOException { } protected Method searchMethod(String internalTypeName, String methodName) throws Exception { - return searchMethod(loader, objectTypeMaker, signatureParser, internalTypeName, methodName, null); + return searchMethod(loader, typeMaker, internalTypeName, methodName, null); } protected Method searchMethod(InputStream is, String internalTypeName, String methodName) throws Exception { @@ -2646,18 +2645,16 @@ protected Method searchMethod(InputStream is, String internalTypeName, String me return null; } else { ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - SignatureParser signatureParser = new SignatureParser(objectTypeMaker); - return searchMethod(loader, objectTypeMaker, signatureParser, internalTypeName, methodName, methodDescriptor); + TypeMaker typeMaker = new TypeMaker(loader); + return searchMethod(loader, typeMaker, internalTypeName, methodName, methodDescriptor); } } - protected Method searchMethod(Loader loader, ObjectTypeMaker objectTypeMaker, SignatureParser signatureParser, String internalTypeName, String methodName, String methodDescriptor) throws Exception { + protected Method searchMethod(Loader loader, TypeMaker typeMaker, String internalTypeName, String methodName, String methodDescriptor) throws Exception { Message message = new Message(); message.setHeader("mainInternalTypeName", internalTypeName); message.setHeader("loader", loader); - message.setHeader("objectTypeMaker", objectTypeMaker); - message.setHeader("signatureParser", signatureParser); + message.setHeader("typeMaker", typeMaker); deserializer.process(message); converter.process(message); diff --git a/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java b/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java index ce79dc68..d64e3308 100644 --- a/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java +++ b/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java @@ -11,7 +11,7 @@ import org.jd.core.v1.loader.ClassPathLoader; import org.jd.core.v1.loader.ZipLoader; import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.junit.Test; import java.io.InputStream; @@ -22,8 +22,8 @@ public class ObjectTypeMakerTest extends TestCase { public void testOuterClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass"); assertEquals("org/jd/core/test/OuterClass", ot.getInternalName()); assertEquals("org.jd.core.test.OuterClass", ot.getQualifiedName()); @@ -34,8 +34,8 @@ public void testOuterClass() throws Exception { public void testOuterClass$InnerClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$InnerClass"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$InnerClass"); assertEquals("org/jd/core/test/OuterClass$InnerClass", ot.getInternalName()); assertEquals("org.jd.core.test.OuterClass.InnerClass", ot.getQualifiedName()); @@ -46,8 +46,8 @@ public void testOuterClass() throws Exception { public void testOuterClass$StaticInnerClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$StaticInnerClass"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$StaticInnerClass"); assertEquals("org/jd/core/test/OuterClass$StaticInnerClass", ot.getInternalName()); assertEquals("org.jd.core.test.OuterClass.StaticInnerClass", ot.getQualifiedName()); @@ -58,8 +58,8 @@ public void testOuterClass() throws Exception { public void testOuterClass$1() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$1"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$1"); assertEquals("org/jd/core/test/OuterClass$1", ot.getInternalName()); assertNull(ot.getQualifiedName()); @@ -70,8 +70,8 @@ public void testOuterClass() throws Exception { public void testOuterClass$1LocalClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$1LocalClass"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$1LocalClass"); assertEquals("org/jd/core/test/OuterClass$1LocalClass", ot.getInternalName()); assertNull(ot.getQualifiedName()); @@ -81,8 +81,8 @@ public void testOuterClass() throws Exception { @Test public void testThread() throws Exception { ClassPathLoader loader = new ClassPathLoader(); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("java/lang/Thread"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("java/lang/Thread"); assertEquals("java/lang/Thread", ot.getInternalName()); assertEquals("java.lang.Thread", ot.getQualifiedName()); @@ -92,8 +92,8 @@ public void testThread() throws Exception { @Test public void testThreadState() throws Exception { ClassPathLoader loader = new ClassPathLoader(); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("java/lang/Thread$State"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("java/lang/Thread$State"); assertEquals("java/lang/Thread$State", ot.getInternalName()); assertEquals("java.lang.Thread.State", ot.getQualifiedName()); @@ -103,8 +103,8 @@ public void testThreadState() throws Exception { @Test public void testUnknownClass() throws Exception { ClassPathLoader loader = new ClassPathLoader(); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("org/unknown/Class"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("org/unknown/Class"); assertEquals("org/unknown/Class", ot.getInternalName()); assertEquals("org.unknown.Class", ot.getQualifiedName()); @@ -114,8 +114,8 @@ public void testUnknownClass() throws Exception { @Test public void testUnknownInnerClass() throws Exception { ClassPathLoader loader = new ClassPathLoader(); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType ot = maker.makeFromInternalTypeName("org/unknown/Class$InnerClass"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType ot = typeMaker.makeFromInternalTypeName("org/unknown/Class$InnerClass"); assertEquals("org/unknown/Class$InnerClass", ot.getInternalName()); assertEquals("org.unknown.Class.InnerClass", ot.getQualifiedName()); @@ -125,76 +125,76 @@ public void testUnknownInnerClass() throws Exception { @Test public void testListIsAssignableFromArrayList() throws Exception { ClassPathLoader loader = new ClassPathLoader(); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType parent = maker.makeFromInternalTypeName("java/util/List"); - ObjectType child = maker.makeFromInternalTypeName("java/util/ArrayList"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType parent = typeMaker.makeFromInternalTypeName("java/util/List"); + ObjectType child = typeMaker.makeFromInternalTypeName("java/util/ArrayList"); assertNotNull(parent); assertNotNull(child); - assertTrue(maker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(parent, child)); } @Test public void testClassIsAssignableFromObject() throws Exception { ClassPathLoader loader = new ClassPathLoader(); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType parent = maker.makeFromInternalTypeName("java/lang/Class"); - ObjectType child = maker.makeFromInternalTypeName("java/lang/Object"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType parent = typeMaker.makeFromInternalTypeName("java/lang/Class"); + ObjectType child = typeMaker.makeFromInternalTypeName("java/lang/Object"); assertNotNull(parent); assertNotNull(child); - assertFalse(maker.isAssignable(parent, child)); + assertFalse(typeMaker.isAssignable(parent, child)); } @Test public void testObjectIsAssignableFromSafeNumberComparator() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType parent = maker.makeFromInternalTypeName("java/lang/Object"); - ObjectType child = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType parent = typeMaker.makeFromInternalTypeName("java/lang/Object"); + ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); assertNotNull(parent); assertNotNull(child); - assertTrue(maker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(parent, child)); } @Test public void testComparatorIsAssignableFromSafeNumberComparator() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType parent = maker.makeFromInternalTypeName("java/util/Comparator"); - ObjectType child = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType parent = typeMaker.makeFromInternalTypeName("java/util/Comparator"); + ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); assertNotNull(parent); assertNotNull(child); - assertTrue(maker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(parent, child)); } @Test public void testNumberComparatorIsAssignableFromSafeNumberComparator() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType parent = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$NumberComparator"); - ObjectType child = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType parent = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$NumberComparator"); + ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); assertNotNull(parent); assertNotNull(child); - assertTrue(maker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(parent, child)); } @Test public void testOuterClassIsAssignableFromSimpleClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker maker = new ObjectTypeMaker(loader); - ObjectType parent = maker.makeFromInternalTypeName("org/jd/core/test/OuterClass"); - ObjectType child = maker.makeFromInternalTypeName("org/jd/core/test/SimpleClass"); + TypeMaker typeMaker = new TypeMaker(loader); + ObjectType parent = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass"); + ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/SimpleClass"); assertNotNull(parent); assertNotNull(child); - assertFalse(maker.isAssignable(parent, child)); + assertFalse(typeMaker.isAssignable(parent, child)); } } diff --git a/src/test/java/org/jd/core/v1/SignatureParserTest.java b/src/test/java/org/jd/core/v1/SignatureParserTest.java index aa810454..8ae9eca4 100644 --- a/src/test/java/org/jd/core/v1/SignatureParserTest.java +++ b/src/test/java/org/jd/core/v1/SignatureParserTest.java @@ -14,8 +14,7 @@ import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.model.message.Message; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.ObjectTypeMaker; -import org.jd.core.v1.service.converter.classfiletojavasyntax.util.SignatureParser; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; import org.jd.core.v1.services.javasyntax.type.visitor.PrintTypeVisitor; import org.junit.Assert; @@ -31,8 +30,7 @@ public void testAnnotatedClass() throws Exception { PrintTypeVisitor visitor = new PrintTypeVisitor(); InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - SignatureParser signatureParser = new SignatureParser(objectTypeMaker); + TypeMaker typeMaker = new TypeMaker(loader); Message message = new Message(); message.setHeader("mainInternalTypeName", "org/jd/core/test/AnnotatedClass"); @@ -43,7 +41,7 @@ public void testAnnotatedClass() throws Exception { ClassFile classFile = message.getBody(); // Check type - SignatureParser.TypeTypes typeTypes = signatureParser.parseClassFileSignature(classFile); + TypeMaker.TypeTypes typeTypes = typeMaker.parseClassFileSignature(classFile); // Check type parameterTypes assertNull(typeTypes.typeParameters); @@ -66,7 +64,7 @@ public void testAnnotatedClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = signatureParser.parseFieldSignature(classFile.getFields()[0]); + Type type = typeMaker.parseFieldSignature(classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -75,16 +73,16 @@ public void testAnnotatedClass() throws Exception { // Check method 'add' // public int add(int i1, int i2) - SignatureParser.MethodTypes methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[1]); + TypeMaker.MethodTypes methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[1]); // Check type parameterTypes assertNull(methodTypes.typeParameters); // Check parameterTypes - assertNotNull(methodTypes.parameters); - assertEquals(2, methodTypes.parameters.size()); + assertNotNull(methodTypes.parameterTypes); + assertEquals(2, methodTypes.parameterTypes.size()); - type = methodTypes.parameters.get(0); + type = methodTypes.parameterTypes.get(0); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -92,10 +90,10 @@ public void testAnnotatedClass() throws Exception { Assert.assertEquals("int", source); // Check return type - assertNotNull(methodTypes.returned); + assertNotNull(methodTypes.returnedType); visitor.reset(); - methodTypes.returned.accept(visitor); + methodTypes.returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("int", source); @@ -105,16 +103,16 @@ public void testAnnotatedClass() throws Exception { // Check method 'ping' // public void ping(String host) throws UnknownHostException, UnsatisfiedLinkError - methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[2]); + methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[2]); // Check type parameterTypes assertNull(methodTypes.typeParameters); // Check parameterTypes - assertNotNull(methodTypes.parameters); - assertEquals(3, methodTypes.parameters.size()); + assertNotNull(methodTypes.parameterTypes); + assertEquals(3, methodTypes.parameterTypes.size()); - type = methodTypes.parameters.get(1); + type = methodTypes.parameterTypes.get(1); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -122,10 +120,10 @@ public void testAnnotatedClass() throws Exception { Assert.assertEquals("java.lang.String", source); // Check return type - assertNotNull(methodTypes.returned); + assertNotNull(methodTypes.returnedType); visitor.reset(); - methodTypes.returned.accept(visitor); + methodTypes.returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("void", source); @@ -145,8 +143,7 @@ public void testGenericClass() throws Exception { PrintTypeVisitor visitor = new PrintTypeVisitor(); InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - SignatureParser signatureParser = new SignatureParser(objectTypeMaker); + TypeMaker typeMaker = new TypeMaker(loader); Message message = new Message(); message.setHeader("mainInternalTypeName", "org/jd/core/test/GenericClass"); @@ -157,7 +154,7 @@ public void testGenericClass() throws Exception { ClassFile classFile = message.getBody(); // Check type - SignatureParser.TypeTypes typeTypes = signatureParser.parseClassFileSignature(classFile); + TypeMaker.TypeTypes typeTypes = typeMaker.parseClassFileSignature(classFile); // Check type parameterTypes // See "org.jd.core.test.resources.java.Generic" @@ -205,7 +202,7 @@ public void testGenericClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = signatureParser.parseFieldSignature(classFile.getFields()[0]); + Type type = typeMaker.parseFieldSignature(classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -214,7 +211,7 @@ public void testGenericClass() throws Exception { // Check method 'copy2' // public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException - SignatureParser.MethodTypes methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[3]); + TypeMaker.MethodTypes methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[3]); // Check type parameterTypes assertNotNull(methodTypes.typeParameters); @@ -225,10 +222,10 @@ public void testGenericClass() throws Exception { Assert.assertEquals("T, S extends T", source); // Check parameterTypes - assertNotNull(methodTypes.parameters); - assertEquals(2, methodTypes.parameters.size()); + assertNotNull(methodTypes.parameterTypes); + assertEquals(2, methodTypes.parameterTypes.size()); - type = methodTypes.parameters.get(0); + type = methodTypes.parameterTypes.get(0); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -236,10 +233,10 @@ public void testGenericClass() throws Exception { Assert.assertEquals("java.util.List", source); // Check return type - assertNotNull(methodTypes.returned); + assertNotNull(methodTypes.returnedType); visitor.reset(); - methodTypes.returned.accept(visitor); + methodTypes.returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("java.util.List", source); @@ -255,7 +252,7 @@ public void testGenericClass() throws Exception { // Check method 'print' // public List print(List list) throws InvalidParameterException, T2 - methodTypes = signatureParser.parseMethodSignature(classFile.getMethods()[4]); + methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[4]); // Check type parameterTypes assertNotNull(methodTypes.typeParameters); @@ -266,10 +263,10 @@ public void testGenericClass() throws Exception { Assert.assertEquals("T1, T2 extends java.lang.Exception", source); // Check parameterTypes - assertNotNull(methodTypes.parameters); - assertEquals(1, methodTypes.parameters.size()); + assertNotNull(methodTypes.parameterTypes); + assertEquals(1, methodTypes.parameterTypes.size()); - type = methodTypes.parameters.get(0); + type = methodTypes.parameterTypes.get(0); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -277,10 +274,10 @@ public void testGenericClass() throws Exception { Assert.assertEquals("java.util.List", source); // Check return type - assertNotNull(methodTypes.returned); + assertNotNull(methodTypes.returnedType); visitor.reset(); - methodTypes.returned.accept(visitor); + methodTypes.returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("java.util.List", source); @@ -299,31 +296,26 @@ public void testGenericClass() throws Exception { public void testParseReturnedVoid() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - SignatureParser signatureParser = new SignatureParser(objectTypeMaker); + TypeMaker typeMaker = new TypeMaker(loader); - Assert.assertEquals(signatureParser.parseReturnedType("()V"), PrimitiveType.TYPE_VOID); + Assert.assertEquals(typeMaker.parseReturnedType("()V"), PrimitiveType.TYPE_VOID); } @Test public void testParseReturnedPrimitiveType() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - SignatureParser signatureParser = new SignatureParser(objectTypeMaker); + TypeMaker typeMaker = new TypeMaker(loader); - Assert.assertEquals(signatureParser.parseReturnedType("()Z"), PrimitiveType.TYPE_BOOLEAN); + Assert.assertEquals(typeMaker.parseReturnedType("()Z"), PrimitiveType.TYPE_BOOLEAN); } @Test public void testParseReturnedStringType() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); ZipLoader loader = new ZipLoader(is); - ObjectTypeMaker objectTypeMaker = new ObjectTypeMaker(loader); - SignatureParser signatureParser = new SignatureParser(objectTypeMaker); + TypeMaker typeMaker = new TypeMaker(loader); - Assert.assertEquals(signatureParser.parseReturnedType("()Ljava/lang/String;"), ObjectType.TYPE_STRING); + Assert.assertEquals(typeMaker.parseReturnedType("()Ljava/lang/String;"), ObjectType.TYPE_STRING); } - - } \ No newline at end of file From aa8d6730ba7310cab6bee29f91cd9c893257c742 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 21 Aug 2019 22:30:53 +0200 Subject: [PATCH 074/211] Improve the generation of generic local variables --- .../processor/ConvertClassFileProcessor.java | 6 +- .../util/ByteCodeParser.java | 132 +++++++++--------- .../util/LocalVariableMaker.java | 4 +- .../classfiletojavasyntax/util/TypeMaker.java | 94 ++++++++++--- .../visitor/InitEnumVisitor.java | 15 +- .../visitor/UpdateBridgeMethodVisitor.java | 77 +++++++++- .../UpdateIntegerConstantTypeVisitor.java | 2 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 3 +- .../org/jd/core/v1/SignatureParserTest.java | 18 +-- 9 files changed, 238 insertions(+), 113 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index af2874d1..d8be69ad 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -128,7 +128,7 @@ protected List convertFields(TypeMaker parser, Annota for (Field field : fields) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, field); - Type typeField = parser.parseFieldSignature(field); + Type typeField = parser.parseFieldSignature(classFile, field); ExpressionVariableInitializer variableInitializer = convertFieldInitializer(field, typeField); FieldDeclarator fieldDeclarator = new FieldDeclarator(field.getName(), variableInitializer); @@ -168,7 +168,7 @@ protected List convertMethods(TypeMaker } if ("".equals(name)) { - TypeMaker.MethodTypes methodTypes = parser.parseConstructorSignature(method); + TypeMaker.MethodTypes methodTypes = parser.parseConstructorSignature(classFile, method); list.add(new ClassFileConstructorDeclaration( bodyDeclaration, classFile, method, annotationReferences, methodTypes.typeParameters, methodTypes.parameterTypes, methodTypes.exceptions, firstLineNumber)); @@ -176,7 +176,7 @@ protected List convertMethods(TypeMaker list.add(new ClassFileStaticInitializerDeclaration(bodyDeclaration, classFile, method, firstLineNumber)); } else { ClassFileMethodDeclaration methodDeclaration; - TypeMaker.MethodTypes methodTypes = parser.parseMethodSignature(method); + TypeMaker.MethodTypes methodTypes = parser.parseMethodSignature(classFile, method); list.add(methodDeclaration = new ClassFileMethodDeclaration( bodyDeclaration, classFile, method, annotationReferences, name, methodTypes.typeParameters, methodTypes.returnedType, methodTypes.parameterTypes, methodTypes.exceptions, defaultAnnotationValue, diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 9300d04e..3649d96e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -43,6 +43,8 @@ import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_PRIVATE; import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_SYNTHETIC; import static org.jd.core.v1.model.javasyntax.statement.ReturnStatement.RETURN; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; @@ -723,13 +725,12 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - DefaultList parameterTypes = typeMaker.parseParameterTypes(descriptor); - BaseExpression parameters = getParameters(statements, stack, parameterTypes); - Type returnedType = typeMaker.parseReturnedType(descriptor); + TypeMaker.MethodTypes methodTypes = typeMaker.makeMethodTypes(ot, name, descriptor); + BaseExpression parameters = getParameters(statements, stack, methodTypes.parameterTypes); if (opcode == 184) { // INVOKESTATIC - expression1 = new ClassFileMethodInvocationExpression(lineNumber, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameterTypes, parameters); - if (TYPE_VOID.equals(returnedType)) { + expression1 = new ClassFileMethodInvocationExpression(lineNumber, methodTypes.returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, methodTypes.parameterTypes, parameters); + if (TYPE_VOID.equals(methodTypes.returnedType)) { statements.add(new ExpressionStatement(expression1)); } else { stack.push(expression1); @@ -742,19 +743,19 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau if (opcode == 185) { // INVOKEINTERFACE offset += 2; // Skip 'count' and one byte } - if (TYPE_VOID.equals(returnedType)) { + if (TYPE_VOID.equals(methodTypes.returnedType)) { if ((opcode == 183) && // INVOKESPECIAL "".equals(name)) { if (expression1.getClass() == ClassFileNewExpression.class) { - ((ClassFileNewExpression)expression1).set(descriptor, parameterTypes, parameters); + ((ClassFileNewExpression)expression1).set(descriptor, methodTypes.parameterTypes, parameters); } else if (ot.getInternalName().equals(((ObjectType)expression1.getType()).getInternalName())) { - statements.add(new ExpressionStatement(new ClassFileConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); + statements.add(new ExpressionStatement(new ClassFileConstructorInvocationExpression(lineNumber, ot, descriptor, methodTypes.parameterTypes, parameters))); } else { - statements.add(new ExpressionStatement(new ClassFileSuperConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); + statements.add(new ExpressionStatement(new ClassFileSuperConstructorInvocationExpression(lineNumber, ot, descriptor, methodTypes.parameterTypes, parameters))); } } else { - statements.add(new ExpressionStatement(new ClassFileMethodInvocationExpression(lineNumber, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters))); + statements.add(new ExpressionStatement(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, methodTypes.parameterTypes, parameters))); } } else { if ((opcode == 182) && // INVOKEVIRTUAL @@ -765,7 +766,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; } } - stack.push(new ClassFileMethodInvocationExpression(lineNumber, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters)); + stack.push(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, methodTypes.parameterTypes, parameters)); } } break; @@ -911,7 +912,7 @@ private BaseExpression getParameters(Statements statements, DefaultStack statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { + private void parseSTORE(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); if ((valueRef.getLineNumber() == lineNumber) && (valueRef.getClass() == BinaryOperatorExpression.class)) { @@ -1158,7 +1159,7 @@ private static boolean stackContainsLocalVariableReference(DefaultStack stack, int lineNumber, FieldReferenceExpression fr, Expression valueRef) { + private void parsePUT(Statements statements, DefaultStack stack, int lineNumber, FieldReferenceExpression fr, Expression valueRef) { if (valueRef.getClass() == NewArray.class) { valueRef = NewArrayMaker.make(statements, (NewArray)valueRef); } @@ -1265,9 +1266,8 @@ private void parseInvokeDynamic(Statements statements, DefaultStack indyParameterTypes = typeMaker.parseParameterTypes(indyDescriptor); - BaseExpression indyParameters = getParameters(statements, stack, indyParameterTypes); - Type indyReturnType = typeMaker.parseReturnedType(indyDescriptor); + TypeMaker.MethodTypes indyMethodTypes = typeMaker.makeMethodTypes(indyDescriptor); + BaseExpression indyParameters = getParameters(statements, stack, indyMethodTypes.parameterTypes); BootstrapMethod bootstrapMethod = attributeBootstrapMethods.getBootstrapMethods()[constantMemberRef.getClassIndex()]; int[] bootstrapArguments = bootstrapMethod.getBootstrapArguments(); @@ -1285,8 +1285,8 @@ private void parseInvokeDynamic(Statements statements, DefaultStack statements, DefaultStack statements, DefaultStack")) { - stack.push(new ConstructorReferenceExpression(lineNumber, indyReturnType, ot, descriptor1)); + stack.push(new ConstructorReferenceExpression(lineNumber, indyMethodTypes.returnedType, ot, descriptor1)); } else { - stack.push(new MethodReferenceExpression(lineNumber, indyReturnType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name1, descriptor1)); + stack.push(new MethodReferenceExpression(lineNumber, indyMethodTypes.returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name1, descriptor1)); } return; } // Create method reference - stack.push(new MethodReferenceExpression(lineNumber, indyReturnType, (Expression)indyParameters, typeName, name1, descriptor1)); + stack.push(new MethodReferenceExpression(lineNumber, indyMethodTypes.returnedType, (Expression)indyParameters, typeName, name1, descriptor1)); } private static List prepareLambdaParameters(BaseFormalParameter formalParameters, int parameterCount) { @@ -1407,9 +1407,7 @@ private void parseASTORE(Statements statements, DefaultStack statements, DefaultStack statements, DefaultStack stack, int lineNumber, Expression leftExpression, Expression rightExpression) { + private void createAssignment(Statements statements, DefaultStack stack, int lineNumber, Expression leftExpression, Expression rightExpression) { if (!stack.isEmpty() && (stack.peek() == rightExpression)) { stack.push(new BinaryOperatorExpression(lineNumber, leftExpression.getType(), leftExpression, "=", stack.pop(), 16)); return; } + rightExpression = checkTypes(leftExpression.getType(), rightExpression); + if (!statements.isEmpty()) { Statement lastStatement = statements.getLast(); @@ -1585,7 +1585,7 @@ private static void parseIF(DefaultStack stack, int lineNumber, Basi @SuppressWarnings("unchecked") private void parseXRETURN(Statements statements, DefaultStack stack, int lineNumber) { - Expression valueRef = checkLocalVariableReferenceExpression(stack.pop(), returnedType); + Expression valueRef = stack.pop(); if (valueRef.getClass() == NewArray.class) { valueRef = NewArrayMaker.make(statements, (NewArray)valueRef); @@ -1613,7 +1613,7 @@ private void parseXRETURN(Statements statements, DefaultStack statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { @@ -1652,9 +1644,9 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan } } - String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.parseTypeSignature(descriptor); ObjectType ot = typeMaker.makeFromInternalTypeName(typeName); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); + Type type = typeMaker.makeFieldType(ot, name, descriptor); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); stack.push(new FieldReferenceExpression(lineNumber, type, objectRef, typeName, name, descriptor)); } @@ -1666,7 +1658,7 @@ private void parsePutStatic(Statements statements, DefaultStack stac ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.parseTypeSignature(descriptor); + Type type = typeMaker.makeFieldType(ot, name, descriptor); Expression valueRef = stack.pop(); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); FieldReferenceExpression fieldRef = new FieldReferenceExpression(lineNumber, type, objectRef, typeName, name, descriptor); @@ -1680,7 +1672,7 @@ private void parseGetField(DefaultStack stack, ConstantPool constant ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.parseTypeSignature(descriptor); + Type type = typeMaker.makeFieldType(ot, name, descriptor); Expression objectRef = stack.pop(); stack.push(new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor)); } @@ -1692,7 +1684,7 @@ private void parsePutField(Statements statements, DefaultStack stack ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.parseTypeSignature(descriptor); + Type type = typeMaker.makeFieldType(ot, name, descriptor); Expression valueRef = stack.pop(); Expression objectRef = stack.pop(); FieldReferenceExpression fieldRef = new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor); @@ -1940,31 +1932,43 @@ private static void checkStack(DefaultStack stack, byte[] code, int } } - private Expression checkLocalVariableReferenceExpression(Expression expression, Type type) { - if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { - AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); + private Expression checkTypes(Type type, Expression expression) { + Class expressionClass = expression.getClass(); + if (expressionClass == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); localVariable.typeOnLeft(type); + } - Type localVariableType = localVariable.getType(); - - if (type.isObject() && localVariableType.isObject() && !localVariableType.equals(type)) { - ObjectType objectType = (ObjectType)type; - ObjectType localVariableObjectType = (ObjectType)localVariableType; - - if (objectType.getInternalName().equals(localVariableObjectType.getInternalName())) { - searchWildcardTypeArgumentVisitor.init(); - localVariableType.accept(searchWildcardTypeArgumentVisitor); - - if (objectType.getTypeArguments() == null) { - if (searchWildcardTypeArgumentVisitor.containsWildcard() || searchWildcardTypeArgumentVisitor.containsWildcardSuperOrExtendsType()) { - ObjectType ot = objectType.createType(null); - return new CastExpression(expression.getLineNumber(), objectType.createType(null), expression); + if (expressionClass != NullExpression.class) { + Type expressionType = expression.getType(); + + if (!expressionType.equals(type) && !TYPE_OBJECT.equals(type)) { + if (type.isObject()) { + if (expressionType.isObject()) { + ObjectType objectType = (ObjectType) type; + ObjectType expressionObjectType = (ObjectType) expressionType; + String internalName = objectType.getInternalName(); + + if (internalName.equals(expressionObjectType.getInternalName()) || typeMaker.isAssignable(objectType, expressionObjectType)) { + if (!internalName.equals(TYPE_CLASS.getInternalName())) { + if (expressionObjectType.getTypeArguments() != null) { + if (expression.getClass() == CastExpression.class) { + ((CastExpression)expression).setType(objectType.createType(null)); + } else { + return new CastExpression(expression.getLineNumber(), objectType.createType(null), expression); + } + } + } } + + // ... + } + } else if (type.isGeneric()) { + if (expression.getClass() == CastExpression.class) { + ((CastExpression)expression).setType(type); } else { - if (searchWildcardTypeArgumentVisitor.containsWildcard() || searchWildcardTypeArgumentVisitor.containsWildcardSuperOrExtendsType()) { - return new CastExpression(expression.getLineNumber(), objectType, expression); - } + return new CastExpression(expression.getLineNumber(), type, expression); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index e7d8c37e..1c66cd41 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -192,7 +192,7 @@ protected void initLocalVariablesFromAttributes(Method method) { if (dimension == 0) { lv = new PrimitiveLocalVariable(index, startPc, PrimitiveType.getPrimitiveType(descriptor.charAt(0)), name); } else { - lv = new ObjectLocalVariable(typeMaker, index, startPc, typeMaker.parseTypeSignature(descriptor.substring(dimension)).createType(dimension), name); + lv = new ObjectLocalVariable(typeMaker, index, startPc, typeMaker.makeFromSignature(descriptor.substring(dimension)).createType(dimension), name); } } @@ -209,7 +209,7 @@ protected void initLocalVariablesFromAttributes(Method method) { for (LocalVariableType lv : localVariableTypeTable.getLocalVariableTypeTable()) { updateTypeVisitor.setLocalVariableType(lv); - typeMaker.parseTypeSignature(lv.getSignature()).accept(updateTypeVisitor); + typeMaker.makeFromSignature(lv.getSignature()).accept(updateTypeVisitor); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index 7699aac9..d58cb777 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -31,8 +31,10 @@ * http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html */ public class TypeMaker { - protected HashMap signatureToMethodTypes = new HashMap<>(1024); protected HashMap signatureToType = new HashMap<>(1024); + protected HashMap internalTypeNameFieldNameToType = new HashMap<>(1024); + protected HashMap internalTypeNameMethodNameDescriptorToMethodTypes = new HashMap<>(1024); + protected HashMap signatureToMethodTypes = new HashMap<>(1024); public TypeMaker(Loader loader) { this.loader = loader; @@ -119,20 +121,22 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { return typeTypes; } - public MethodTypes parseConstructorSignature(Method method) { + public MethodTypes parseConstructorSignature(ClassFile classFile, Method method) { + String key = classFile.getInternalTypeName() + ":" + method.getDescriptor(); AttributeSignature attributeSignature = method.getAttribute("Signature"); + MethodTypes methodTypes; if (attributeSignature == null) { - return parseMethodSignature(method.getDescriptor(), method); + methodTypes = parseMethodSignature(method.getDescriptor(), method); } else { // Signature does not contain synthetic parameterTypes like outer type name, for example. MethodTypes mt1 = parseMethodSignature(attributeSignature.getSignature(), method); MethodTypes mt2 = parseMethodSignature(method.getDescriptor(), method); if (mt1.parameterTypes.size() == mt2.parameterTypes.size()) { - return mt1; + methodTypes = mt1; } else if (mt1.parameterTypes.isEmpty() && (mt1.typeParameters == null)) { - return mt2; + methodTypes = mt2; } else { DefaultList parameters = new DefaultList<>(mt2.parameterTypes); @@ -146,24 +150,38 @@ public MethodTypes parseConstructorSignature(Method method) { mt3.returnedType = mt1.returnedType; mt3.exceptions = mt1.exceptions; - return mt3; + methodTypes = mt3; } } + + internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes); + + return methodTypes; } - public MethodTypes parseMethodSignature(Method method) { + public MethodTypes parseMethodSignature(ClassFile classFile, Method method) { + String key = classFile.getInternalTypeName() + ':' + method.getName() + method.getDescriptor(); AttributeSignature attributeSignature = method.getAttribute("Signature"); String signature = (attributeSignature == null) ? method.getDescriptor() : attributeSignature.getSignature(); - return parseMethodSignature(signature, method); + MethodTypes methodTypes = parseMethodSignature(signature, method); + + internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes); + + return methodTypes; } - public Type parseFieldSignature(Field field) { + public Type parseFieldSignature(ClassFile classFile, Field field) { + String key = classFile.getInternalTypeName() + ':' + field.getName(); AttributeSignature attributeSignature = field.getAttribute("Signature"); String signature = (attributeSignature == null) ? field.getDescriptor() : attributeSignature.getSignature(); - return parseTypeSignature(signature); + Type type = makeFromSignature(signature); + + internalTypeNameFieldNameToType.put(key, type); + + return type; } - public Type parseTypeSignature(String signature) { + public Type makeFromSignature(String signature) { Type type = signatureToType.get(signature); if (type == null) { @@ -175,16 +193,6 @@ public Type parseTypeSignature(String signature) { return type; } - public DefaultList parseParameterTypes(String signature) { - MethodTypes methodTypes = parseMethodSignature(signature, null); - return (methodTypes==null) ? DefaultList.emptyList() : methodTypes.parameterTypes; - } - - public Type parseReturnedType(String signature) { - MethodTypes methodTypes = parseMethodSignature(signature, null); - return (methodTypes==null) ? null : methodTypes.returnedType; - } - public static int countDimension(String descriptor) { int count = 0; @@ -1252,4 +1260,48 @@ private static void skipAttributes(ClassFileReader reader) { reader.skip(attributeLength); } } + + public MethodTypes makeMethodTypes(String descriptor) { + return parseMethodSignature(descriptor, null); + } + + public MethodTypes makeMethodTypes(ObjectType objectType, String methodName, String descriptor) { + if (objectType.getDimension() == 0) { + String key = objectType.getInternalName() + ':' + methodName + descriptor; + + if (internalTypeNameMethodNameDescriptorToMethodTypes.containsKey(key)) { + MethodTypes methodTypes = internalTypeNameMethodNameDescriptorToMethodTypes.get(key); + + if (methodTypes != null) { + if (methodTypes.typeParameters == null) { + return methodTypes; + } + } + } else { + // Search method + // ... + } + } + + return parseMethodSignature(descriptor, null); + } + + public Type makeFieldType(ObjectType objectType, String fieldName, String descriptor) { + if (objectType.getDimension() == 0) { + String key = objectType.getInternalName() + ':' + fieldName; + + if (internalTypeNameFieldNameToType.containsKey(key)) { + Type type = internalTypeNameFieldNameToType.get(key); + + if (type != null) { + return type; + } + } else { + // Search field + // ... + } + } + + return makeFromSignature(descriptor); + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java index bc20fab6..e862f9a8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java @@ -9,10 +9,7 @@ import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.declaration.*; -import org.jd.core.v1.model.javasyntax.expression.BaseExpression; -import org.jd.core.v1.model.javasyntax.expression.Expressions; -import org.jd.core.v1.model.javasyntax.expression.IntegerConstantExpression; -import org.jd.core.v1.model.javasyntax.expression.NewExpression; +import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.Statements; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; import org.jd.core.v1.util.DefaultList; @@ -98,8 +95,14 @@ public void visit(FieldDeclarator declaration) { @Override public void visit(NewExpression expression) { - Expressions parameters = (Expressions)expression.getParameters(); - IntegerConstantExpression ice = (IntegerConstantExpression)parameters.get(1); + Expressions parameters = (Expressions)expression.getParameters(); + Expression exp = parameters.get(1); + + if (exp.getClass() == CastExpression.class) { + exp = ((CastExpression)exp).getExpression(); + } + + IntegerConstantExpression ice = (IntegerConstantExpression)exp; lineNumber = expression.getLineNumber(); index = ice.getValue(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java index a000a3a6..b9ac3ab9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -67,12 +67,29 @@ protected Expression updateExpression(Expression expression) { } Class expClass = exp.getClass(); + + if (expClass == CastExpression.class) { + exp = ((CastExpression)exp).getExpression(); + expClass = exp.getClass(); + } + int parameterTypesCount = methodBridgeDeclaration.getParameterTypes().size(); if (expClass == FieldReferenceExpression.class) { FieldReferenceExpression fre = (FieldReferenceExpression) exp; - expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); + if (parameterTypesCount == 0) { + expression = fre.getExpression(); + } else { + expression = mie1.getParameters().getFirst(); + if (expression.getClass() == CastExpression.class) { + CastExpression ce = (CastExpression)expression; + if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { + // Remove cast expression + expression = ce.getExpression(); + } + } + } return new FieldReferenceExpression(mie1.getLineNumber(), mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()); } else if (expClass == ClassFileMethodInvocationExpression.class) { @@ -99,18 +116,36 @@ protected Expression updateExpression(Expression expression) { } } - return new MethodInvocationExpression(mie1.getLineNumber(), mie2.getType(), mie1Parameters.getFirst(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameters); + expression = mie1Parameters.getFirst(); + if (expression.getClass() == CastExpression.class) { + CastExpression ce = (CastExpression)expression; + if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { + // Remove cast expression + expression = ce.getExpression(); + } + } + + return new MethodInvocationExpression(mie1.getLineNumber(), mie2.getType(), expression, mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameters); } } else if (expClass == BinaryOperatorExpression.class) { BinaryOperatorExpression boe = (BinaryOperatorExpression) exp; FieldReferenceExpression fre = (FieldReferenceExpression) boe.getLeftExpression(); if (parameterTypesCount == 1) { + expression = mie1.getParameters().getFirst(); + if (expression.getClass() == CastExpression.class) { + CastExpression ce = (CastExpression)expression; + if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { + // Remove cast expression + expression = ce.getExpression(); + } + } + return new BinaryOperatorExpression( mie1.getLineNumber(), mie1.getType(), new FieldReferenceExpression(fre.getType(), fre.getExpression(), fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()), boe.getOperator(), - mie1.getParameters().getFirst(), + expression, boe.getPriority()); } else if (parameterTypesCount == 2) { DefaultList parameters = mie1.getParameters().getList(); @@ -126,7 +161,18 @@ protected Expression updateExpression(Expression expression) { PostOperatorExpression poe = (PostOperatorExpression)exp; FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); - expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); + if (parameterTypesCount == 0) { + expression = fre.getExpression(); + } else { + expression = mie1.getParameters().getFirst(); + if (expression.getClass() == CastExpression.class) { + CastExpression ce = (CastExpression)expression; + if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { + // Remove cast expression + expression = ce.getExpression(); + } + } + } return new PostOperatorExpression( mie1.getLineNumber(), @@ -136,7 +182,18 @@ protected Expression updateExpression(Expression expression) { PreOperatorExpression poe = (PreOperatorExpression)exp; FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); - expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); + if (parameterTypesCount == 0) { + expression = fre.getExpression(); + } else { + expression = mie1.getParameters().getFirst(); + if (expression.getClass() == CastExpression.class) { + CastExpression ce = (CastExpression)expression; + if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { + // Remove cast expression + expression = ce.getExpression(); + } + } + } return new PreOperatorExpression( mie1.getLineNumber(), @@ -223,6 +280,12 @@ private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMe } Class expClass = exp.getClass(); + + if (expClass == CastExpression.class) { + exp = ((CastExpression)exp).getExpression(); + expClass = exp.getClass(); + } + int parameterTypesCount = bridgeMethodDeclaration.getParameterTypes().size(); if (expClass == FieldReferenceExpression.class) { @@ -329,6 +392,10 @@ private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMe } private boolean checkLocalVariableReference(BaseExpression expression, int index) { + if (expression.getClass() == CastExpression.class) { + expression = ((CastExpression)expression).getExpression(); + } + if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { return false; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 2adc9b9a..217404a9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -346,7 +346,7 @@ protected BaseExpression updateExpressions(List types, BaseExpression expr } protected Expression updateExpression(Type type, Expression expression) { - assert (type != TYPE_VOID); + assert type != TYPE_VOID : "UpdateIntegerConstantTypeVisitor.updateExpression(type, expr) : try to set 'void' to a numeric expression"; if (type != expression.getType()) { Class clazz = expression.getClass(); diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 1d8da050..4bc1bb27 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -29,7 +29,6 @@ import java.util.HashMap; import java.util.Map; - public class ClassFileToJavaSourceTest extends TestCase { protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); @@ -2062,7 +2061,7 @@ public void testJdk170GenericClass() throws Exception { assertTrue(source.indexOf("public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException") != -1); assertTrue(source.indexOf("public List print(List list) throws T2, InvalidParameterException") != -1); - assertTrue(source.matches(PatternMaker.make(": 100 */", "return (T1)call(0);"))); + assertTrue(source.matches(PatternMaker.make(": 100 */", "return call(0);"))); assertTrue(source.matches(PatternMaker.make(": 104 */", "return (T1)this;"))); assertTrue(source.indexOf("/* 104: 104 */") != -1); diff --git a/src/test/java/org/jd/core/v1/SignatureParserTest.java b/src/test/java/org/jd/core/v1/SignatureParserTest.java index 8ae9eca4..04c1c839 100644 --- a/src/test/java/org/jd/core/v1/SignatureParserTest.java +++ b/src/test/java/org/jd/core/v1/SignatureParserTest.java @@ -64,7 +64,7 @@ public void testAnnotatedClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = typeMaker.parseFieldSignature(classFile.getFields()[0]); + Type type = typeMaker.parseFieldSignature(classFile, classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -73,7 +73,7 @@ public void testAnnotatedClass() throws Exception { // Check method 'add' // public int add(int i1, int i2) - TypeMaker.MethodTypes methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[1]); + TypeMaker.MethodTypes methodTypes = typeMaker.parseMethodSignature(classFile, classFile.getMethods()[1]); // Check type parameterTypes assertNull(methodTypes.typeParameters); @@ -103,7 +103,7 @@ public void testAnnotatedClass() throws Exception { // Check method 'ping' // public void ping(String host) throws UnknownHostException, UnsatisfiedLinkError - methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[2]); + methodTypes = typeMaker.parseMethodSignature(classFile, classFile.getMethods()[2]); // Check type parameterTypes assertNull(methodTypes.typeParameters); @@ -202,7 +202,7 @@ public void testGenericClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = typeMaker.parseFieldSignature(classFile.getFields()[0]); + Type type = typeMaker.parseFieldSignature(classFile, classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -211,7 +211,7 @@ public void testGenericClass() throws Exception { // Check method 'copy2' // public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException - TypeMaker.MethodTypes methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[3]); + TypeMaker.MethodTypes methodTypes = typeMaker.parseMethodSignature(classFile, classFile.getMethods()[3]); // Check type parameterTypes assertNotNull(methodTypes.typeParameters); @@ -252,7 +252,7 @@ public void testGenericClass() throws Exception { // Check method 'print' // public List print(List list) throws InvalidParameterException, T2 - methodTypes = typeMaker.parseMethodSignature(classFile.getMethods()[4]); + methodTypes = typeMaker.parseMethodSignature(classFile, classFile.getMethods()[4]); // Check type parameterTypes assertNotNull(methodTypes.typeParameters); @@ -298,7 +298,7 @@ public void testParseReturnedVoid() throws Exception { ZipLoader loader = new ZipLoader(is); TypeMaker typeMaker = new TypeMaker(loader); - Assert.assertEquals(typeMaker.parseReturnedType("()V"), PrimitiveType.TYPE_VOID); + Assert.assertEquals(typeMaker.makeMethodTypes("()V").returnedType, PrimitiveType.TYPE_VOID); } @Test @@ -307,7 +307,7 @@ public void testParseReturnedPrimitiveType() throws Exception { ZipLoader loader = new ZipLoader(is); TypeMaker typeMaker = new TypeMaker(loader); - Assert.assertEquals(typeMaker.parseReturnedType("()Z"), PrimitiveType.TYPE_BOOLEAN); + Assert.assertEquals(typeMaker.makeMethodTypes("()Z").returnedType, PrimitiveType.TYPE_BOOLEAN); } @Test @@ -316,6 +316,6 @@ public void testParseReturnedStringType() throws Exception { ZipLoader loader = new ZipLoader(is); TypeMaker typeMaker = new TypeMaker(loader); - Assert.assertEquals(typeMaker.parseReturnedType("()Ljava/lang/String;"), ObjectType.TYPE_STRING); + Assert.assertEquals(typeMaker.makeMethodTypes("()Ljava/lang/String;").returnedType, ObjectType.TYPE_STRING); } } \ No newline at end of file From 90d5e76c3a29ec115411c3af6541c7b94a273df7 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 21 Aug 2019 22:31:22 +0200 Subject: [PATCH 075/211] Update version to 1.0.9 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a34401a6..d11990d6 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'org.apache.commons:commons-collections4:4.1' } -version='1.0.7' +version='1.0.9' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From 57b5bb9e3c4589cad958624f8d7efdb359dee5e0 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 4 Sep 2019 19:14:58 +0200 Subject: [PATCH 076/211] Fix syntax errors in decompiled sources --- .../javasyntax/AbstractJavaSyntaxVisitor.java | 8 +- .../declaration/AnnotationDeclaration.java | 4 +- .../declaration/ClassDeclaration.java | 2 +- .../declaration/EnumDeclaration.java | 4 +- .../declaration/InterfaceDeclaration.java | 4 +- .../declaration/ModuleDeclaration.java | 4 +- .../declaration/TypeDeclaration.java | 12 +- .../javasyntax/type/ArrayTypeArguments.java | 14 +- .../javasyntax/type/BaseTypeArgument.java | 15 + .../v1/model/javasyntax/type/GenericType.java | 10 +- .../v1/model/javasyntax/type/ObjectType.java | 4 +- .../ClassFileToJavaSyntaxProcessor.java | 24 +- .../ClassFileAnnotationDeclaration.java | 4 +- .../declaration/ClassFileBodyDeclaration.java | 4 +- .../ClassFileClassDeclaration.java | 2 +- .../ClassFileConstructorDeclaration.java | 10 +- ...assFileConstructorOrMethodDeclaration.java | 7 +- .../declaration/ClassFileEnumDeclaration.java | 4 +- .../ClassFileInterfaceDeclaration.java | 4 +- .../ClassFileMethodDeclaration.java | 14 +- ...ClassFileStaticInitializerDeclaration.java | 7 +- ...ssFileConstructorInvocationExpression.java | 9 +- .../ClassFileMethodInvocationExpression.java | 15 +- .../expression/ClassFileNewExpression.java | 9 +- ...eSuperConstructorInvocationExpression.java | 9 +- .../localvariable/ObjectLocalVariable.java | 9 +- .../localvariable/PrimitiveLocalVariable.java | 32 +- .../UpdateJavaSyntaxTreeProcessor.java | 2 +- .../util/ByteCodeParser.java | 315 +++-- .../util/LocalVariableMaker.java | 50 +- .../util/LoopStatementMaker.java | 16 +- .../util/StatementMaker.java | 6 +- .../util/StringConcatenationUtil.java | 17 +- .../classfiletojavasyntax/util/TypeMaker.java | 1251 +++++++++-------- .../visitor/AddCastExpressionVisitor.java | 308 ++++ .../visitor/CreateInstructionsVisitor.java | 14 +- .../visitor/InitEnumVisitor.java | 1 + .../visitor/InitInnerClassVisitor.java | 99 +- .../visitor/InitStaticFieldVisitor.java | 8 +- .../RemoveDefaultConstructorVisitor.java | 28 +- ....java => SearchInTypeArgumentVisitor.java} | 22 +- .../visitor/UpdateBridgeMethodVisitor.java | 109 +- .../UpdateIntegerConstantTypeVisitor.java | 35 +- .../UpdateJavaSyntaxTreeStep2Visitor.java | 23 +- .../classfile/ClassFileDeserializer.java | 13 +- .../visitor/CompilationUnitVisitor.java | 14 +- .../visitor/ExpressionVisitor.java | 6 +- .../visitor/TypeVisitor.java | 9 +- src/main/java/org/jd/core/v1/util/Base.java | 6 +- .../java/org/jd/core/v1/util/DefaultList.java | 6 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 4 +- .../jd/core/v1/JarFileToJavaSourceTest.java | 15 +- .../org/jd/core/v1/SignatureParserTest.java | 51 +- .../jd/core/v1/loader/DirectoryLoader.java | 55 + .../resources/java/org/jd/core/test/Enum.java | 4 +- 55 files changed, 1761 insertions(+), 970 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java rename src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/{SearchWildcardTypeArgumentVisitor.java => SearchInTypeArgumentVisitor.java} (69%) create mode 100644 src/test/java/org/jd/core/v1/loader/DirectoryLoader.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java index 7d8a67b5..6ab49a93 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -87,7 +87,7 @@ public void visit(Expressions list) { @Override public void visit(ExpressionVariableInitializer declaration) { - safeAccept(declaration.getExpression()); + declaration.getExpression().accept(this); } @Override @@ -98,8 +98,8 @@ public void visit(FieldDeclaration declaration) { } @Override - public void visit(FieldDeclarator declaration) { - safeAccept(declaration.getVariableInitializer()); + public void visit(FieldDeclarator declarator) { + safeAccept(declarator.getVariableInitializer()); } @Override diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java index 4566ed5f..7413f52f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -34,6 +34,6 @@ public void accept(DeclarationVisitor visitor) { @Override public String toString() { - return "AnnotationDeclaration{" + internalName + "}"; + return "AnnotationDeclaration{" + internalTypeName + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java index 670678bb..0070ab3b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java @@ -35,6 +35,6 @@ public void accept(DeclarationVisitor visitor) { @Override public String toString() { - return "ClassDeclaration{" + internalName + "}"; + return "ClassDeclaration{" + internalTypeName + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java index 07bf9d1b..e40775f7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -50,7 +50,7 @@ public void accept(DeclarationVisitor visitor) { @Override public String toString() { - return "EnumDeclaration{" + internalName + "}"; + return "EnumDeclaration{" + internalTypeName + "}"; } public static class Constant implements Declaration { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java index f8db8d46..ede8720e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -47,6 +47,6 @@ public void accept(DeclarationVisitor visitor) { @Override public String toString() { - return "InterfaceDeclaration{" + internalName + "}"; + return "InterfaceDeclaration{" + internalTypeName + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java index 918dd187..bb3226d4 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -41,7 +41,7 @@ public void accept(DeclarationVisitor visitor) { @Override public String toString() { - return "ModuleDeclaration{" + internalName + "}"; + return "ModuleDeclaration{" + internalTypeName + "}"; } public static class ModuleInfo { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java index f404bb14..6dbc674b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -12,13 +12,13 @@ public abstract class TypeDeclaration implements BaseTypeDeclaration, MemberDeclaration { protected BaseAnnotationReference annotationReferences; protected int flags; - protected String internalName; + protected String internalTypeName; protected String name; - protected TypeDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name) { + protected TypeDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalTypeName, String name) { this.annotationReferences = annotationReferences; this.flags = flags; - this.internalName = internalName; + this.internalTypeName = internalTypeName; this.name = name; } @@ -30,8 +30,8 @@ public int getFlags() { return flags; } - public String getInternalName() { - return internalName; + public String getInternalTypeName() { + return internalTypeName; } public String getName() { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java index df1784a5..7caf7402 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java @@ -20,8 +20,8 @@ public ArrayTypeArguments(List list) { } @Override - public void accept(TypeVisitor visitor) { - visitor.visit(this); + public boolean isList() { + return true; } @Override @@ -47,4 +47,14 @@ public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { return true; } + + @Override + public int typeArgumentSize() { + return size(); + } + + @Override + public void accept(TypeVisitor visitor) { + visitor.visit(this); + } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java index 24d9330f..9625a078 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java @@ -7,6 +7,21 @@ package org.jd.core.v1.model.javasyntax.type; +import org.jd.core.v1.util.DefaultList; + +@SuppressWarnings("unchecked") public interface BaseTypeArgument extends TypeVisitable { boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument); + + default TypeArgument getTypeArgumentFirst() { + return (TypeArgument)this; + } + + default DefaultList getTypeArgumentList() { + return (DefaultList)this; + } + + default int typeArgumentSize() { + return 1; + } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java index 964ca3d6..a6f84905 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java @@ -67,7 +67,15 @@ public void accept(TypeVisitor visitor) { @Override public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { - return equals(typeArgument); + if (typeArgument.getClass() == GenericType.class) { + return true; + } else if (typeArgument instanceof Type) { + return true; + } else if (typeArgument instanceof WildcardTypeArgument) { + return false; + } + + return false; } @Override diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index 96208935..384b1cbe 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -204,8 +204,8 @@ public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { } if (ot.getTypeArguments() == null) { - return (typeArgument == null); - } else if (typeArgument == null) { + return (typeArguments == null); + } else if (typeArguments == null) { return false; } else { return typeArguments.isTypeArgumentAssignableFrom(ot.getTypeArguments()); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java index a0136c67..d166c679 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/ClassFileToJavaSyntaxProcessor.java @@ -14,6 +14,8 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.processor.UpdateJavaSyntaxTreeProcessor; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; +import java.util.Map; + /** * Convert ClassFile model to Java syntax model.

* @@ -28,10 +30,28 @@ public class ClassFileToJavaSyntaxProcessor implements Processor { public void process(Message message) throws Exception { Loader loader = message.getHeader("loader"); + Map configuration = message.getHeader("configuration"); + + if (configuration == null) { + message.setHeader("typeMaker", new TypeMaker(loader)); + } else { + TypeMaker typeMaker = null; + + try { + typeMaker = (TypeMaker)configuration.get("typeMaker"); - TypeMaker typeMaker = new TypeMaker(loader); + if (typeMaker == null) { + // Store the heavy weight object 'typeMaker' in 'configuration' to reuse it + configuration.put("typeMaker", typeMaker=new TypeMaker(loader)); + } + } catch (Exception e) { + if (typeMaker == null) { + typeMaker = new TypeMaker(loader); + } + } - message.setHeader("typeMaker", typeMaker); + message.setHeader("typeMaker", typeMaker); + } CONVERT_CLASS_FILE_PROCESSOR.process(message); UPDATE_JAVA_SYNTAX_TREE_PROCESSOR.process(message); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java index 5e1c5576..0f0b7f5b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -25,6 +25,6 @@ public int getFirstLineNumber() { @Override public String toString() { - return "ClassFileAnnotationDeclaration{" + internalName + ", firstLineNumber=" + firstLineNumber + "}"; + return "ClassFileAnnotationDeclaration{" + internalTypeName + ", firstLineNumber=" + firstLineNumber + "}"; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java index 31e5376d..83978654 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -73,7 +73,7 @@ public void setInnerTypeDeclarations(List innerTypeD for (ClassFileMemberDeclaration innerType : innerTypeDeclarations) { TypeDeclaration td = (TypeDeclaration) innerType; - innerTypeMap.put(td.getInternalName(), innerType); + innerTypeMap.put(td.getInternalTypeName(), innerType); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java index 2e912010..3baff3af 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java @@ -32,6 +32,6 @@ public void setFlags(int flags) { @Override public String toString() { - return "ClassFileClassDeclaration{" + internalName + ", firstLineNumber=" + firstLineNumber + "}"; + return "ClassFileClassDeclaration{" + internalTypeName + ", firstLineNumber=" + firstLineNumber + "}"; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java index a502bc45..93cbc5b6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -17,18 +17,16 @@ import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; -import java.util.List; - public class ClassFileConstructorDeclaration extends ConstructorDeclaration implements ClassFileConstructorOrMethodDeclaration { protected ClassFileBodyDeclaration bodyDeclaration; protected ClassFile classFile; protected Method method; - protected List parameterTypes; + protected BaseType parameterTypes; protected int firstLineNumber; public ClassFileConstructorDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, BaseAnnotationReference annotationReferences, - BaseTypeParameter typeParameters, List parameterTypes, BaseType exceptions, int firstLineNumber) { + BaseTypeParameter typeParameters, BaseType parameterTypes, BaseType exceptions, int firstLineNumber) { super(annotationReferences, method.getAccessFlags(), typeParameters, null, exceptions, method.getDescriptor(), null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; @@ -68,7 +66,7 @@ public Method getMethod() { } @Override - public List getParameterTypes() { + public BaseType getParameterTypes() { return parameterTypes; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java index 27d9db07..4bfc009f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,10 +11,9 @@ import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.model.javasyntax.declaration.BaseFormalParameter; import org.jd.core.v1.model.javasyntax.statement.BaseStatement; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.Type; -import java.util.List; - public interface ClassFileConstructorOrMethodDeclaration extends ClassFileMemberDeclaration { int getFlags(); void setFlags(int flags); @@ -23,7 +22,7 @@ public interface ClassFileConstructorOrMethodDeclaration extends ClassFileMember Method getMethod(); - List getParameterTypes(); + BaseType getParameterTypes(); Type getReturnedType(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java index 8a510667..ed3c282d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -37,7 +37,7 @@ public int getFirstLineNumber() { @Override public String toString() { - return "ClassFileEnumDeclaration{" + internalName + ", firstLineNumber=" + firstLineNumber + "}"; + return "ClassFileEnumDeclaration{" + internalTypeName + ", firstLineNumber=" + firstLineNumber + "}"; } public static class ClassFileConstant extends Constant { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java index 57456e02..224dfd4b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -27,6 +27,6 @@ public int getFirstLineNumber() { @Override public String toString() { - return "ClassFileInterfaceDeclaration{" + internalName + ", firstLineNumber=" + firstLineNumber + "}"; + return "ClassFileInterfaceDeclaration{" + internalTypeName + ", firstLineNumber=" + firstLineNumber + "}"; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java index 1d70b382..cc5ed19c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -18,18 +18,16 @@ import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; -import java.util.List; - public class ClassFileMethodDeclaration extends MethodDeclaration implements ClassFileConstructorOrMethodDeclaration { protected ClassFileBodyDeclaration bodyDeclaration; protected ClassFile classFile; protected Method method; - protected List parameterTypes; + protected BaseType parameterTypes; protected int firstLineNumber; public ClassFileMethodDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, String name, - Type returnedType, List parameterTypes) { + Type returnedType, BaseType parameterTypes) { super(null, method.getAccessFlags(), name, null, returnedType, null, null, method.getDescriptor(), null, null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; @@ -39,7 +37,7 @@ public ClassFileMethodDeclaration( public ClassFileMethodDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, String name, - Type returnedType, List parameterTypes, int firstLineNumber) { + Type returnedType, BaseType parameterTypes, int firstLineNumber) { super(null, method.getAccessFlags(), name, null, returnedType, null, null, method.getDescriptor(), null, null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; @@ -50,7 +48,7 @@ public ClassFileMethodDeclaration( public ClassFileMethodDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, BaseAnnotationReference annotationReferences, - String name, BaseTypeParameter typeParameters, Type returnedType, List parameterTypes, BaseType exceptions, + String name, BaseTypeParameter typeParameters, Type returnedType, BaseType parameterTypes, BaseType exceptions, ElementValue defaultAnnotationValue, int firstLineNumber) { super(annotationReferences, method.getAccessFlags(), name, typeParameters, returnedType, null, exceptions, method.getDescriptor(), null, defaultAnnotationValue); this.bodyDeclaration = bodyDeclaration; @@ -91,7 +89,7 @@ public Method getMethod() { } @Override - public List getParameterTypes() { + public BaseType getParameterTypes() { return parameterTypes; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java index 95dac1fe..44132a07 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -12,10 +12,9 @@ import org.jd.core.v1.model.javasyntax.declaration.BaseFormalParameter; import org.jd.core.v1.model.javasyntax.declaration.StaticInitializerDeclaration; import org.jd.core.v1.model.javasyntax.statement.BaseStatement; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.Type; -import java.util.List; - public class ClassFileStaticInitializerDeclaration extends StaticInitializerDeclaration implements ClassFileConstructorOrMethodDeclaration { protected ClassFileBodyDeclaration bodyDeclaration; protected ClassFile classFile; @@ -53,7 +52,7 @@ public ClassFile getClassFile() { public Method getMethod() { return method; } @Override - public List getParameterTypes() { + public BaseType getParameterTypes() { return null; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java index 2b0c8c0b..1c5d7f81 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java @@ -9,19 +9,18 @@ import org.jd.core.v1.model.javasyntax.expression.BaseExpression; import org.jd.core.v1.model.javasyntax.expression.ConstructorInvocationExpression; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.util.DefaultList; public class ClassFileConstructorInvocationExpression extends ConstructorInvocationExpression { - protected DefaultList parameterTypes; + protected BaseType parameterTypes; - public ClassFileConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + public ClassFileConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, BaseType parameterTypes, BaseExpression parameters) { super(lineNumber, type, descriptor, parameters); this.parameterTypes = parameterTypes; } - public DefaultList getParameterTypes() { + public BaseType getParameterTypes() { return parameterTypes; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java index 688f4ad1..ea4a704b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java @@ -10,18 +10,25 @@ import org.jd.core.v1.model.javasyntax.expression.BaseExpression; import org.jd.core.v1.model.javasyntax.expression.Expression; import org.jd.core.v1.model.javasyntax.expression.MethodInvocationExpression; +import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.util.DefaultList; public class ClassFileMethodInvocationExpression extends MethodInvocationExpression { - protected DefaultList parameterTypes; + protected BaseTypeParameter typeParameters; + protected BaseType parameterTypes; - public ClassFileMethodInvocationExpression(int lineNumber, Type type, Expression expression, String internalTypeName, String name, String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + public ClassFileMethodInvocationExpression(int lineNumber, BaseTypeParameter typeParameters, Type type, Expression expression, String internalTypeName, String name, String descriptor, BaseType parameterTypes, BaseExpression parameters) { super(lineNumber, type, expression, internalTypeName, name, descriptor, parameters); + this.typeParameters = typeParameters; this.parameterTypes = parameterTypes; } - public DefaultList getParameterTypes() { + public BaseTypeParameter getTypeParameters() { + return typeParameters; + } + + public BaseType getParameterTypes() { return parameterTypes; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java index 8044afb5..f79d6d6b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java @@ -10,12 +10,11 @@ import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; import org.jd.core.v1.model.javasyntax.expression.BaseExpression; import org.jd.core.v1.model.javasyntax.expression.NewExpression; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.util.DefaultList; public class ClassFileNewExpression extends NewExpression { - protected DefaultList parameterTypes; + protected BaseType parameterTypes; public ClassFileNewExpression(int lineNumber, ObjectType type) { super(lineNumber, type); @@ -25,11 +24,11 @@ public ClassFileNewExpression(int lineNumber, ObjectType type, BodyDeclaration b super(lineNumber, type, bodyDeclaration); } - public DefaultList getParameterTypes() { + public BaseType getParameterTypes() { return parameterTypes; } - public void set(String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + public void set(String descriptor, BaseType parameterTypes, BaseExpression parameters) { this.descriptor = descriptor; this.parameterTypes = parameterTypes; this.parameters = parameters; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java index a1424877..48c86c81 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java @@ -9,19 +9,18 @@ import org.jd.core.v1.model.javasyntax.expression.BaseExpression; import org.jd.core.v1.model.javasyntax.expression.SuperConstructorInvocationExpression; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.Type; -import org.jd.core.v1.util.DefaultList; public class ClassFileSuperConstructorInvocationExpression extends SuperConstructorInvocationExpression { - protected DefaultList parameterTypes; + protected BaseType parameterTypes; - public ClassFileSuperConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, DefaultList parameterTypes, BaseExpression parameters) { + public ClassFileSuperConstructorInvocationExpression(int lineNumber, ObjectType type, String descriptor, BaseType parameterTypes, BaseExpression parameters) { super(lineNumber, type, descriptor, parameters); this.parameterTypes = parameterTypes; } - public DefaultList getParameterTypes() { + public BaseType getParameterTypes() { return parameterTypes; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 72ea9513..54b4f4de 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -80,7 +80,7 @@ public String toString() { @Override public boolean isAssignableFrom(Type type) { if (!type.isPrimitive()) { - if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_OBJECT) || this.type.equals(type)) { + if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || TYPE_OBJECT.equals(this.type) || this.type.equals(type)) { return true; } else if ((this.type.getDimension() == type.getDimension()) && this.type.isObject()) { ObjectType thisObjectType = (ObjectType) this.type; @@ -134,7 +134,9 @@ public void typeOnRight(Type type) { fireChangeEvent(); } } - } else if (type.isGeneric() && thisObjectType.getInternalName().equals(TYPE_OBJECT.getInternalName())) { + } + } else if (this.type.isGeneric()) { + if (type.isGeneric()) { this.type = type; fireChangeEvent(); } @@ -171,9 +173,6 @@ public void typeOnLeft(Type type) { fireChangeEvent(); } } - } else if (type.isGeneric() && thisObjectType.getInternalName().equals(TYPE_OBJECT.getInternalName())) { - this.type = type; - fireChangeEvent(); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java index 3695071e..5790556e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java @@ -129,34 +129,38 @@ public boolean isAssignableFrom(Type type) { @Override public void typeOnRight(Type type) { - assert (type.getDimension() == 0); + if (type.isPrimitive()) { + assert (type.getDimension() == 0); - int f = ((PrimitiveType)type).getRightFlags(); + int f = ((PrimitiveType) type).getRightFlags(); - if ((flags & f) != 0) { - int old = flags; + if ((flags & f) != 0) { + int old = flags; - flags &= f; + flags &= f; - if (old != flags) { - fireChangeEvent(); + if (old != flags) { + fireChangeEvent(); + } } } } @Override public void typeOnLeft(Type type) { - assert (type.getDimension() == 0); + if (type.isPrimitive()) { + assert (type.getDimension() == 0); - int f = ((PrimitiveType)type).getLeftFlags(); + int f = ((PrimitiveType) type).getLeftFlags(); - if ((flags & f) != 0) { - int old = flags; + if ((flags & f) != 0) { + int old = flags; - flags &= f; + flags &= f; - if (old != flags) { - fireChangeEvent(); + if (old != flags) { + fireChangeEvent(); + } } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java index 0cc5dc4c..7a3b495e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/UpdateJavaSyntaxTreeProcessor.java @@ -30,7 +30,7 @@ public void process(Message message) throws Exception { UpdateJavaSyntaxTreeStep1Visitor updateJavaSyntaxTreeStep1Visitor = new UpdateJavaSyntaxTreeStep1Visitor(typeMaker); updateJavaSyntaxTreeStep1Visitor.visit(compilationUnit); - UpdateJavaSyntaxTreeStep2Visitor updateJavaSyntaxTreeStep2Visitor = new UpdateJavaSyntaxTreeStep2Visitor(); + UpdateJavaSyntaxTreeStep2Visitor updateJavaSyntaxTreeStep2Visitor = new UpdateJavaSyntaxTreeStep2Visitor(typeMaker); updateJavaSyntaxTreeStep2Visitor.visit(compilationUnit); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 3649d96e..67b30790 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -18,10 +18,7 @@ import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; -import org.jd.core.v1.model.javasyntax.type.GenericType; -import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.PrimitiveType; -import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; @@ -31,11 +28,11 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.PrimitiveLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; -import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchWildcardTypeArgumentVisitor; import org.jd.core.v1.util.DefaultList; import org.jd.core.v1.util.DefaultStack; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -43,7 +40,6 @@ import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_PRIVATE; import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_SYNTHETIC; import static org.jd.core.v1.model.javasyntax.statement.ReturnStatement.RETURN; -import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; @@ -56,20 +52,17 @@ public class ByteCodeParser { private String internalTypeName; private AttributeBootstrapMethods attributeBootstrapMethods; private ClassFileBodyDeclaration bodyDeclaration; - private Type returnedType; private MemberVisitor memberVisitor = new MemberVisitor(); private SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); - private SearchWildcardTypeArgumentVisitor searchWildcardTypeArgumentVisitor = new SearchWildcardTypeArgumentVisitor(); public ByteCodeParser( TypeMaker typeMaker, LocalVariableMaker localVariableMaker, String internalTypeName, - ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration, Type returnedType) { + ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration) { this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; this.internalTypeName = internalTypeName; this.attributeBootstrapMethods = classFile.getAttribute("BootstrapMethods"); this.bodyDeclaration = bodyDeclaration; - this.returnedType = returnedType; } @SuppressWarnings("unchecked") @@ -726,10 +719,13 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); TypeMaker.MethodTypes methodTypes = typeMaker.makeMethodTypes(ot, name, descriptor); - BaseExpression parameters = getParameters(statements, stack, methodTypes.parameterTypes); + BaseExpression parameters = extractParametersFromStack(statements, stack, methodTypes.parameterTypes); if (opcode == 184) { // INVOKESTATIC - expression1 = new ClassFileMethodInvocationExpression(lineNumber, methodTypes.returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, methodTypes.parameterTypes, parameters); + Type returnedType = bindParameterTypesWithArgumentTypes(ot, methodTypes.returnedType); + BaseType parameterTypes = bindParameterTypesWithArgumentTypes(ot, methodTypes.parameterTypes); + parameters = prepareParameters(parameters, parameterTypes); + expression1 = new ClassFileMethodInvocationExpression(lineNumber, methodTypes.typeParameters, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameterTypes, parameters); if (TYPE_VOID.equals(methodTypes.returnedType)) { statements.add(new ExpressionStatement(expression1)); } else { @@ -737,25 +733,29 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } } else { expression1 = stack.pop(); + Type returnedType = bindParameterTypesWithArgumentTypes(ot, methodTypes.returnedType); + BaseType parameterTypes = bindParameterTypesWithArgumentTypes(ot, methodTypes.parameterTypes); + //BaseType parameterTypes = bindParameterTypesWithArgumentTypes(expression1, ot, methodTypes.parameterTypes); + parameters = prepareParameters(parameters, parameterTypes); if (expression1.getClass() == ClassFileLocalVariableReferenceExpression.class) { ((ClassFileLocalVariableReferenceExpression)expression1).getLocalVariable().typeOnLeft(ot); } if (opcode == 185) { // INVOKEINTERFACE offset += 2; // Skip 'count' and one byte } - if (TYPE_VOID.equals(methodTypes.returnedType)) { + if (TYPE_VOID.equals(returnedType)) { if ((opcode == 183) && // INVOKESPECIAL "".equals(name)) { if (expression1.getClass() == ClassFileNewExpression.class) { - ((ClassFileNewExpression)expression1).set(descriptor, methodTypes.parameterTypes, parameters); - } else if (ot.getInternalName().equals(((ObjectType)expression1.getType()).getInternalName())) { - statements.add(new ExpressionStatement(new ClassFileConstructorInvocationExpression(lineNumber, ot, descriptor, methodTypes.parameterTypes, parameters))); + ((ClassFileNewExpression)expression1).set(descriptor, parameterTypes, parameters); + } else if (ot.getDescriptor().equals(expression1.getType().getDescriptor())) { + statements.add(new ExpressionStatement(new ClassFileConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); } else { - statements.add(new ExpressionStatement(new ClassFileSuperConstructorInvocationExpression(lineNumber, ot, descriptor, methodTypes.parameterTypes, parameters))); + statements.add(new ExpressionStatement(new ClassFileSuperConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); } } else { - statements.add(new ExpressionStatement(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, methodTypes.parameterTypes, parameters))); + statements.add(new ExpressionStatement(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.typeParameters, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters))); } } else { if ((opcode == 182) && // INVOKEVIRTUAL @@ -766,7 +766,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; } } - stack.push(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, methodTypes.parameterTypes, parameters)); + stack.push(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.typeParameters, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters)); } } break; @@ -903,7 +903,11 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } @SuppressWarnings("unchecked") - private BaseExpression getParameters(Statements statements, DefaultStack stack, DefaultList parameterTypes) { + private BaseExpression extractParametersFromStack(Statements statements, DefaultStack stack, BaseType parameterTypes) { + if (parameterTypes == null) { + return null; + } + switch (parameterTypes.size()) { case 0: return null; @@ -912,7 +916,7 @@ private BaseExpression getParameters(Statements statements, DefaultStack list = parameterTypes.getList(); + int count = list.size(); + + for (int i=0; i types = new Types<>(list); + for (i=0; i bind = new HashMap<>(); + + switch (expressionTypeArguments.typeArgumentSize()) { + case 0: + break; + case 1: + bind.put(typeParameters.getFirst(), expressionTypeArguments.getTypeArgumentFirst()); + break; + default: + Iterator typeParameterIterator = typeParameters.getList().iterator(); + Iterator typeArgumentIterator = expressionTypeArguments.getTypeArgumentList().iterator(); + + while (typeParameterIterator.hasNext()) { + bind.put(typeParameterIterator.next(), typeArgumentIterator.next()); + } + break; + } + + // Replace + switch (parameterTypes.size()) { + case 0: + return parameterTypes; + case 1: + Type parameterType = parameterTypes.getFirst(); + TypeArgument typeArgument = bind.get(parameterType); + + if (typeArgument == null) { + return parameterType; + } else { + return (typeArgument instanceof Type) ? (Type)typeArgument : TYPE_OBJECT; + } + default: + DefaultList list = parameterTypes.getList(); + int count = list.size(); + + for (int i=0; i types = new Types<>(list); + for (i=0; i 1) { + DefaultList parameters = parameterExpressions.getList(); + DefaultList types = parameterTypes.getList(); + + for (int i=0; i statements, Expression parameter) { if (!statements.isEmpty()) { Statement lastStatement = statements.getLast(); @@ -953,14 +1126,24 @@ private static Expression checkIfLastStatementIsAMultiAssignment(Statements statements, DefaultStack statements, DefaultStack statements, DefaultStack statements, DefaultStack statements, DefaultStack statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { @@ -1705,23 +1886,30 @@ private static Expression getLastRightExpression(BinaryOperatorExpression boe) { } } - private Expression newNewExpression(int lineNumber, String internalName) { - ObjectType objectType = typeMaker.makeFromInternalTypeName(internalName); + private Expression newNewExpression(int lineNumber, String internalTypeName) { + ObjectType objectType = typeMaker.makeFromInternalTypeName(internalTypeName); if ((objectType.getQualifiedName() == null) && (objectType.getName() == null)) { - ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); + ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalTypeName); if (memberDeclaration == null) { return new ClassFileNewExpression(lineNumber, ObjectType.TYPE_OBJECT); } else if (memberDeclaration.getClass() == ClassFileClassDeclaration.class) { ClassFileClassDeclaration declaration = (ClassFileClassDeclaration) memberDeclaration; + BodyDeclaration bodyDeclaration; + + if (this.internalTypeName.equals(internalTypeName)) { + bodyDeclaration = null; + } else { + bodyDeclaration = declaration.getBodyDeclaration(); + } if (declaration.getInterfaces() != null) { - return new ClassFileNewExpression(lineNumber, (ObjectType) declaration.getInterfaces(), declaration.getBodyDeclaration()); + return new ClassFileNewExpression(lineNumber, (ObjectType) declaration.getInterfaces(), bodyDeclaration); } else if (declaration.getSuperType() != null) { - return new ClassFileNewExpression(lineNumber, (ObjectType) declaration.getSuperType(), declaration.getBodyDeclaration()); + return new ClassFileNewExpression(lineNumber, declaration.getSuperType(), bodyDeclaration); } else { - return new ClassFileNewExpression(lineNumber, ObjectType.TYPE_OBJECT, declaration.getBodyDeclaration()); + return new ClassFileNewExpression(lineNumber, ObjectType.TYPE_OBJECT, bodyDeclaration); } } } @@ -1932,51 +2120,6 @@ private static void checkStack(DefaultStack stack, byte[] code, int } } - private Expression checkTypes(Type type, Expression expression) { - Class expressionClass = expression.getClass(); - - if (expressionClass == ClassFileLocalVariableReferenceExpression.class) { - AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); - localVariable.typeOnLeft(type); - } - - if (expressionClass != NullExpression.class) { - Type expressionType = expression.getType(); - - if (!expressionType.equals(type) && !TYPE_OBJECT.equals(type)) { - if (type.isObject()) { - if (expressionType.isObject()) { - ObjectType objectType = (ObjectType) type; - ObjectType expressionObjectType = (ObjectType) expressionType; - String internalName = objectType.getInternalName(); - - if (internalName.equals(expressionObjectType.getInternalName()) || typeMaker.isAssignable(objectType, expressionObjectType)) { - if (!internalName.equals(TYPE_CLASS.getInternalName())) { - if (expressionObjectType.getTypeArguments() != null) { - if (expression.getClass() == CastExpression.class) { - ((CastExpression)expression).setType(objectType.createType(null)); - } else { - return new CastExpression(expression.getLineNumber(), objectType.createType(null), expression); - } - } - } - } - - // ... - } - } else if (type.isGeneric()) { - if (expression.getClass() == CastExpression.class) { - ((CastExpression)expression).setType(type); - } else { - return new CastExpression(expression.getLineNumber(), type, expression); - } - } - } - } - - return expression; - } - public static boolean isAssertCondition(String internalTypeName, BasicBlock basicBlock) { ControlFlowGraph cfg = basicBlock.getControlFlowGraph(); int offset = basicBlock.getFromOffset(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 1c66cd41..f493b491 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -15,18 +15,15 @@ import org.jd.core.v1.model.javasyntax.declaration.FormalParameters; import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; import org.jd.core.v1.model.javasyntax.statement.Statements; -import org.jd.core.v1.model.javasyntax.type.InnerObjectType; -import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.PrimitiveType; -import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFormalParameter; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.*; +import org.jd.core.v1.util.DefaultList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import static org.jd.core.v1.model.javasyntax.declaration.MethodDeclaration.*; @@ -41,11 +38,12 @@ public class LocalVariableMaker { protected FormalParameters formalParameters; protected PopulateBlackListNamesVisitor populateBlackListNamesVisitor = new PopulateBlackListNamesVisitor(blackListNames); + protected SearchInTypeArgumentVisitor searchInTypeArgumentVisitor = new SearchInTypeArgumentVisitor(); protected CreateParameterVisitor createParameterVisitor; protected CreateLocalVariableVisitor createLocalVariableVisitor; @SuppressWarnings("unchecked") - public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDeclaration comdwln, boolean constructor, List parameterTypes) { + public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDeclaration comdwln, boolean constructor, BaseType parameterTypes) { ClassFile classFile = comdwln.getClassFile(); Method method = comdwln.getMethod(); @@ -79,8 +77,12 @@ public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDecla } if (parameterTypes != null) { - for (Type type : parameterTypes) { - type.accept(populateBlackListNamesVisitor); + if (parameterTypes.isList()) { + for (Type type : parameterTypes.getList()) { + type.accept(populateBlackListNamesVisitor); + } + } else { + parameterTypes.getFirst().accept(populateBlackListNamesVisitor); } } @@ -120,7 +122,7 @@ public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDecla } } - if ((parameterTypes != null) && !parameterTypes.isEmpty()) { + if ((parameterTypes != null) && (parameterTypes != null)) { int lastParameterIndex = parameterTypes.size() - 1; boolean varargs = ((method.getAccessFlags() & FLAG_VARARGS) != 0); @@ -215,11 +217,12 @@ protected void initLocalVariablesFromAttributes(Method method) { } } - protected void initLocalVariablesFromParameterTypes(ClassFile classFile, List parameterTypes, boolean varargs, int firstVariableIndex, int lastParameterIndex) { + protected void initLocalVariablesFromParameterTypes(ClassFile classFile, BaseType parameterTypes, boolean varargs, int firstVariableIndex, int lastParameterIndex) { HashMap typeMap = new HashMap<>(); + DefaultList t = parameterTypes.getList(); for (int parameterIndex=0; parameterIndex<=lastParameterIndex; parameterIndex++) { - Type type = parameterTypes.get(parameterIndex); + Type type = t.get(parameterIndex); typeMap.put(type, Boolean.valueOf(typeMap.containsKey(type))); } @@ -241,7 +244,7 @@ protected void initLocalVariablesFromParameterTypes(ClassFile classFile, List Create a new local variable diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index c9e202f4..bd0bc0c6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -18,6 +18,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForEachStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.ObjectLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.CreateTypeFromTypeArgumentVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.RemoveLastContinueStatementVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; @@ -503,8 +504,13 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake subStatements.removeLast(); item.setDeclared(true); - Type itemType = arrayType.createType(arrayType.getDimension()-1); - item.typeOnRight(itemType); + Type type = arrayType.createType(arrayType.getDimension()-1); + + if (ObjectType.TYPE_OBJECT.equals(item.getType())) { + ((ObjectLocalVariable)item).setType(type); + } else { + item.typeOnRight(type); + } localVariableMaker.removeLocalVariable(syntheticArray); localVariableMaker.removeLocalVariable(syntheticIndex); @@ -633,7 +639,11 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker Type type = visitor2.getType(); if (type != null) { - item.typeOnRight(type); + if (ObjectType.TYPE_OBJECT.equals(item.getType())) { + ((ObjectLocalVariable)item).setType(type); + } else { + item.typeOnRight(type); + } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 097af2d3..8d2082fc 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -53,7 +53,7 @@ public class StatementMaker { protected DefaultStack stack = new DefaultStack<>(); protected RemoveFinallyStatementsVisitor removeFinallyStatementsVisitor; protected RemoveBinaryOpReturnStatementsVisitor removeBinaryOpReturnStatementsVisitor; - protected final UpdateIntegerConstantTypeVisitor updateIntegerConstantTypeVisitor; + protected UpdateIntegerConstantTypeVisitor updateIntegerConstantTypeVisitor; protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); protected MemberVisitor memberVisitor = new MemberVisitor(); protected boolean removeFinallyStatementsFlag = false; @@ -67,7 +67,7 @@ public StatementMaker( this.majorVersion = classFile.getMajorVersion(); this.internalTypeName = classFile.getInternalTypeName(); this.bodyDeclaration = bodyDeclaration; - this.byteCodeParser = new ByteCodeParser(typeMaker, localVariableMaker, internalTypeName, classFile, bodyDeclaration, returnedType); + this.byteCodeParser = new ByteCodeParser(typeMaker, localVariableMaker, internalTypeName, classFile, bodyDeclaration); this.removeFinallyStatementsVisitor = new RemoveFinallyStatementsVisitor(localVariableMaker); this.removeBinaryOpReturnStatementsVisitor = new RemoveBinaryOpReturnStatementsVisitor(localVariableMaker); this.updateIntegerConstantTypeVisitor = new UpdateIntegerConstantTypeVisitor(returnedType); @@ -823,7 +823,7 @@ protected static void changeEndLoopToStartLoop(BitSet visited, BasicBlock basicB } protected Expression parseTernaryOperator(int lineNumber, Expression condition, Expression exp1, Expression exp2) { - if ((exp1.getType() == ObjectType.TYPE_CLASS) && (exp2.getType() == ObjectType.TYPE_CLASS) && (condition.getClass() == BinaryOperatorExpression.class)) { + if (ObjectType.TYPE_CLASS.equals(exp1.getType()) && ObjectType.TYPE_CLASS.equals(exp2.getType()) && (condition.getClass() == BinaryOperatorExpression.class)) { BinaryOperatorExpression boeCond = (BinaryOperatorExpression) condition; if ((boeCond.getLeftExpression().getClass() == FieldReferenceExpression.class) && (boeCond.getRightExpression().getClass() == NullExpression.class)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java index e796193a..b10568e1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java @@ -21,17 +21,19 @@ public static Expression create(Expression expression, int lineNumber, String ty if (expression.getClass() == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie = (MethodInvocationExpression) expression; - if ("append".equals(mie.getName()) && (mie.getParameters() != null) && !mie.getParameters().isList()) { + if ((mie.getParameters() != null) && !mie.getParameters().isList() && "append".equals(mie.getName())) { Expression concatenatedStringExpression = mie.getParameters().getFirst(); Expression expr = mie.getExpression(); + boolean firstParameterHaveGenericType = false; while (expr.getClass() == ClassFileMethodInvocationExpression.class) { mie = (MethodInvocationExpression) expr; - if (("append".equals(mie.getName()) == false) || (mie.getParameters() == null) || mie.getParameters().isList()) { + if ((mie.getParameters() == null) || mie.getParameters().isList() || !"append".equals(mie.getName())) { break; } + firstParameterHaveGenericType = mie.getParameters().getFirst().getType().isGeneric(); concatenatedStringExpression = new BinaryOperatorExpression(mie.getLineNumber(), ObjectType.TYPE_STRING, (Expression) mie.getParameters(), "+", concatenatedStringExpression, 4); expr = mie.getExpression(); } @@ -42,12 +44,13 @@ public static Expression create(Expression expression, int lineNumber, String ty if ("Ljava/lang/StringBuilder;".equals(internalTypeName) || "Ljava/lang/StringBuffer;".equals(internalTypeName)) { if (ne.getParameters() == null) { - return concatenatedStringExpression; - } - if (!ne.getParameters().isList()) { + if (!firstParameterHaveGenericType) { + return concatenatedStringExpression; + } + } else if (!ne.getParameters().isList()) { expression = ne.getParameters().getFirst(); - if (expression.getType() == ObjectType.TYPE_STRING) { + if (ObjectType.TYPE_STRING.equals(expression.getType())) { return new BinaryOperatorExpression(ne.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", concatenatedStringExpression, 4); } } @@ -56,7 +59,7 @@ public static Expression create(Expression expression, int lineNumber, String ty } } - return new MethodInvocationExpression(lineNumber, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;"); + return new ClassFileMethodInvocationExpression(lineNumber, null, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;", null, null); } public static Expression create(String recipe, BaseExpression parameters) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index d58cb777..76a62cad 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -8,17 +8,18 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; import org.jd.core.v1.model.classfile.ClassFile; import org.jd.core.v1.model.classfile.Field; import org.jd.core.v1.model.classfile.Method; -import org.jd.core.v1.model.classfile.attribute.AttributeExceptions; -import org.jd.core.v1.model.classfile.attribute.AttributeSignature; -import org.jd.core.v1.model.classfile.constant.ConstantClass; +import org.jd.core.v1.model.classfile.attribute.*; import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.deserializer.classfile.ClassFileFormatException; import org.jd.core.v1.service.deserializer.classfile.ClassFileReader; -import org.jd.core.v1.util.DefaultList; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; @@ -31,10 +32,31 @@ * http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html */ public class TypeMaker { - protected HashMap signatureToType = new HashMap<>(1024); - protected HashMap internalTypeNameFieldNameToType = new HashMap<>(1024); - protected HashMap internalTypeNameMethodNameDescriptorToMethodTypes = new HashMap<>(1024); - protected HashMap signatureToMethodTypes = new HashMap<>(1024); + private static final HashMap INTERNALNAME_TO_OBJECTPRIMITIVETYPE = new HashMap<>(); + + static { + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_BOOLEAN.getInternalName(), ObjectType.TYPE_PRIMITIVE_BOOLEAN); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_BYTE.getInternalName(), ObjectType.TYPE_PRIMITIVE_BYTE); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_CHAR.getInternalName(), ObjectType.TYPE_PRIMITIVE_CHAR); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_DOUBLE.getInternalName(), ObjectType.TYPE_PRIMITIVE_DOUBLE); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_FLOAT.getInternalName(), ObjectType.TYPE_PRIMITIVE_FLOAT); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_INT.getInternalName(), ObjectType.TYPE_PRIMITIVE_INT); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_LONG.getInternalName(), ObjectType.TYPE_PRIMITIVE_LONG); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_SHORT.getInternalName(), ObjectType.TYPE_PRIMITIVE_SHORT); + INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_VOID.getInternalName(), ObjectType.TYPE_PRIMITIVE_VOID); + } + + private HashMap signatureToType = new HashMap<>(1024); + private HashMap internalTypeNameFieldNameToType = new HashMap<>(1024); + private HashMap descriptorToObjectType = new HashMap<>(1024); + private HashMap internalTypeNameToObjectType = new HashMap<>(1024); + private HashMap internalTypeNameMethodNameDescriptorToMethodTypes = new HashMap<>(1024); + private HashMap signatureToMethodTypes = new HashMap<>(1024); + private HashMap internalTypeNameToTypeParameters = new HashMap<>(1024); + + private HashMap hierarchy = new HashMap<>(1024); + private ClassPathLoader classPathLoader = new ClassPathLoader(); + private Loader loader; public TypeMaker(Loader loader) { this.loader = loader; @@ -46,10 +68,28 @@ public TypeMaker(Loader loader) { signatureToType.put("I", PrimitiveType.TYPE_INT); signatureToType.put("J", PrimitiveType.TYPE_LONG); signatureToType.put("S", PrimitiveType.TYPE_SHORT); + signatureToType.put("V", PrimitiveType.TYPE_VOID); signatureToType.put("Z", PrimitiveType.TYPE_BOOLEAN); - signatureToType.put("java/lang/Class", ObjectType.TYPE_CLASS); - signatureToType.put("java/lang/Object", ObjectType.TYPE_OBJECT); - signatureToType.put("java/lang/String", ObjectType.TYPE_STRING); + signatureToType.put("Ljava/lang/Class;", ObjectType.TYPE_CLASS); + signatureToType.put("Ljava/lang/Exception;", ObjectType.TYPE_EXCEPTION); + signatureToType.put("Ljava/lang/Object;", ObjectType.TYPE_OBJECT); + signatureToType.put("Ljava/lang/Throwable;", ObjectType.TYPE_THROWABLE); + signatureToType.put("Ljava/lang/String;", ObjectType.TYPE_STRING); + signatureToType.put("Ljava/lang/System;", ObjectType.TYPE_SYSTEM); + + descriptorToObjectType.put("Ljava/lang/Class;", ObjectType.TYPE_CLASS); + descriptorToObjectType.put("Ljava/lang/Exception;", ObjectType.TYPE_EXCEPTION); + descriptorToObjectType.put("Ljava/lang/Object;", ObjectType.TYPE_OBJECT); + descriptorToObjectType.put("Ljava/lang/Throwable;", ObjectType.TYPE_THROWABLE); + descriptorToObjectType.put("Ljava/lang/String;", ObjectType.TYPE_STRING); + descriptorToObjectType.put("Ljava/lang/System;", ObjectType.TYPE_SYSTEM); + + internalTypeNameToObjectType.put("java/lang/Class", ObjectType.TYPE_CLASS); + internalTypeNameToObjectType.put("java/lang/Exception", ObjectType.TYPE_EXCEPTION); + internalTypeNameToObjectType.put("java/lang/Object", ObjectType.TYPE_OBJECT); + internalTypeNameToObjectType.put("java/lang/Throwable", ObjectType.TYPE_THROWABLE); + internalTypeNameToObjectType.put("java/lang/String", ObjectType.TYPE_STRING); + internalTypeNameToObjectType.put("java/lang/System", ObjectType.TYPE_SYSTEM); } /** @@ -123,35 +163,23 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { public MethodTypes parseConstructorSignature(ClassFile classFile, Method method) { String key = classFile.getInternalTypeName() + ":" + method.getDescriptor(); + return parseConstructorOrMethodSignature(method, key); + } + + public MethodTypes parseMethodSignature(ClassFile classFile, Method method) { + String key = classFile.getInternalTypeName() + ':' + method.getName() + method.getDescriptor(); + return parseConstructorOrMethodSignature(method, key); + } + + private MethodTypes parseConstructorOrMethodSignature(Method method, String key) { AttributeSignature attributeSignature = method.getAttribute("Signature"); + String[] exceptionTypeNames = getExceptionTypeNames(method); MethodTypes methodTypes; if (attributeSignature == null) { - methodTypes = parseMethodSignature(method.getDescriptor(), method); + methodTypes = parseMethodSignature(method.getDescriptor(), exceptionTypeNames); } else { - // Signature does not contain synthetic parameterTypes like outer type name, for example. - MethodTypes mt1 = parseMethodSignature(attributeSignature.getSignature(), method); - MethodTypes mt2 = parseMethodSignature(method.getDescriptor(), method); - - if (mt1.parameterTypes.size() == mt2.parameterTypes.size()) { - methodTypes = mt1; - } else if (mt1.parameterTypes.isEmpty() && (mt1.typeParameters == null)) { - methodTypes = mt2; - } else { - DefaultList parameters = new DefaultList<>(mt2.parameterTypes); - - parameters.subList(1, 1+mt1.parameterTypes.size()).clear(); - parameters.addAll(1, mt1.parameterTypes); - - MethodTypes mt3 = new MethodTypes(); - - mt3.typeParameters = mt1.typeParameters; - mt3.parameterTypes = parameters; - mt3.returnedType = mt1.returnedType; - mt3.exceptions = mt1.exceptions; - - methodTypes = mt3; - } + methodTypes = parseMethodSignature(method.getDescriptor(), attributeSignature.getSignature(), exceptionTypeNames); } internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes); @@ -159,15 +187,16 @@ public MethodTypes parseConstructorSignature(ClassFile classFile, Method method) return methodTypes; } - public MethodTypes parseMethodSignature(ClassFile classFile, Method method) { - String key = classFile.getInternalTypeName() + ':' + method.getName() + method.getDescriptor(); - AttributeSignature attributeSignature = method.getAttribute("Signature"); - String signature = (attributeSignature == null) ? method.getDescriptor() : attributeSignature.getSignature(); - MethodTypes methodTypes = parseMethodSignature(signature, method); + private static String[] getExceptionTypeNames(Method method) { + if (method != null) { + AttributeExceptions attributeExceptions = method.getAttribute("Exceptions"); - internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes); + if (attributeExceptions != null) { + return attributeExceptions.getExceptionTypeNames(); + } + } - return methodTypes; + return null; } public Type parseFieldSignature(ClassFile classFile, Field field) { @@ -203,6 +232,44 @@ public static int countDimension(String descriptor) { return count; } + private MethodTypes parseMethodSignature(String descriptor, String signature, String[] exceptionTypeNames) { + if (signature == null) { + return parseMethodSignature(descriptor, exceptionTypeNames); + } else { + // Signature does not contain synthetic parameterTypes like outer type name, for example. + MethodTypes mtDescriptor = parseMethodSignature(descriptor, exceptionTypeNames); + MethodTypes mtSignature = parseMethodSignature(signature, exceptionTypeNames); + + if (mtDescriptor.parameterTypes == null) { + return mtSignature; + } else if (mtSignature.parameterTypes == null) { + MethodTypes mt = new MethodTypes(); + + mt.typeParameters = mtSignature.typeParameters; + mt.parameterTypes = mtDescriptor.parameterTypes; + mt.returnedType = mtSignature.returnedType; + mt.exceptions = mtSignature.exceptions; + + return mt; + } else if (mtDescriptor.parameterTypes.size() == mtSignature.parameterTypes.size()) { + return mtSignature; + } else { + Types parameterTypes = new Types<>(mtDescriptor.parameterTypes.getList()); + parameterTypes.subList(parameterTypes.size() - mtSignature.parameterTypes.size(), parameterTypes.size()).clear(); + parameterTypes.addAll(mtSignature.parameterTypes.getList()); + + MethodTypes mt = new MethodTypes(); + + mt.typeParameters = mtSignature.typeParameters; + mt.parameterTypes = parameterTypes; + mt.returnedType = mtSignature.returnedType; + mt.exceptions = mtSignature.exceptions; + + return mt; + } + } + } + /** * Rules: * MethodTypeSignature: TypeParameters? '(' ReferenceTypeSignature* ')' ReturnType ThrowsSignature* @@ -210,22 +277,18 @@ public static int countDimension(String descriptor) { * ThrowsSignature: '^' ClassTypeSignature | '^' TypeVariableSignature */ @SuppressWarnings("unchecked") - protected MethodTypes parseMethodSignature(String signature, Method method) { + private MethodTypes parseMethodSignature(String signature, String[] exceptionTypeNames) { String cacheKey = signature; boolean containsThrowsSignature = (signature.indexOf('^') != -1); - if (!containsThrowsSignature && (method != null)) { - AttributeExceptions attributeExceptions = method.getAttribute("Exceptions"); - - if (attributeExceptions != null) { - StringBuilder sb = new StringBuilder(signature); - - for (String exceptionTypeName : attributeExceptions.getExceptionTypeNames()) { - sb.append("^L").append(exceptionTypeName).append(';'); - } + if (!containsThrowsSignature && (exceptionTypeNames != null)) { + StringBuilder sb = new StringBuilder(signature); - cacheKey = sb.toString(); + for (String exceptionTypeName : exceptionTypeNames) { + sb.append("^L").append(exceptionTypeName).append(';'); } + + cacheKey = sb.toString(); } MethodTypes methodTypes = signatureToMethodTypes.get(cacheKey); @@ -238,29 +301,31 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { methodTypes.typeParameters = parseTypeParameters(reader); // Parameters - if (reader.read() != '(') + if (reader.read() != '(') { throw new SignatureFormatException(signature); + } - Type firstParameter = parseReferenceTypeSignature(reader); + Type firstParameterType = parseReferenceTypeSignature(reader); - if (firstParameter == null) { - methodTypes.parameterTypes = DefaultList.emptyList(); + if (firstParameterType == null) { + methodTypes.parameterTypes = null; } else { - Type nextParameter = parseReferenceTypeSignature(reader); - DefaultList list = new DefaultList<>(); + Type nextParameterType = parseReferenceTypeSignature(reader); + Types types = new Types(); - list.add(firstParameter); + types.add(firstParameterType); - while (nextParameter != null) { - list.add(nextParameter); - nextParameter = parseReferenceTypeSignature(reader); + while (nextParameterType != null) { + types.add(nextParameterType); + nextParameterType = parseReferenceTypeSignature(reader); } - methodTypes.parameterTypes = list; + methodTypes.parameterTypes = types; } - if (reader.read() != ')') + if (reader.read() != ')') { throw new SignatureFormatException(signature); + } // Result methodTypes.returnedType = parseReferenceTypeSignature(reader); @@ -270,23 +335,17 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { if (firstException == null) { // Signature does not contain exceptions - if (method != null) { - AttributeExceptions attributeExceptions = method.getAttribute("Exceptions"); - - if (attributeExceptions != null) { - String[] exceptionTypeNames = attributeExceptions.getExceptionTypeNames(); - - if (exceptionTypeNames.length == 1) { - methodTypes.exceptions = makeFromInternalTypeName(exceptionTypeNames[0]); - } else { - Types list = new Types(exceptionTypeNames.length); - - for (String exceptionTypeName : exceptionTypeNames) { - list.add(makeFromInternalTypeName(exceptionTypeName)); - } + if (exceptionTypeNames != null) { + if (exceptionTypeNames.length == 1) { + methodTypes.exceptions = makeFromInternalTypeName(exceptionTypeNames[0]); + } else { + Types list = new Types(exceptionTypeNames.length); - methodTypes.exceptions = list; + for (String exceptionTypeName : exceptionTypeNames) { + list.add(makeFromInternalTypeName(exceptionTypeName)); } + + methodTypes.exceptions = list; } } } else { @@ -319,15 +378,16 @@ protected MethodTypes parseMethodSignature(String signature, Method method) { * TypeParameters: '<' TypeParameter+ '>' */ @SuppressWarnings("unchecked") - protected BaseTypeParameter parseTypeParameters(SignatureReader reader) { + private BaseTypeParameter parseTypeParameters(SignatureReader reader) { if (reader.nextEqualsTo('<')) { // Skip '<' reader.index++; TypeParameter firstTypeParameter = parseTypeParameter(reader); - if (firstTypeParameter == null) + if (firstTypeParameter == null) { throw new SignatureFormatException(reader.signature); + } TypeParameter nextTypeParameter = parseTypeParameter(reader); BaseTypeParameter typeParameters; @@ -346,8 +406,9 @@ protected BaseTypeParameter parseTypeParameters(SignatureReader reader) { typeParameters = list; } - if (reader.read() != '>') + if (reader.read() != '>') { throw new SignatureFormatException(reader.signature); + } return typeParameters; } else { @@ -362,7 +423,7 @@ protected BaseTypeParameter parseTypeParameters(SignatureReader reader) { * InterfaceBound: ':' FieldTypeSignature */ @SuppressWarnings("unchecked") - protected TypeParameter parseTypeParameter(SignatureReader reader) { + private TypeParameter parseTypeParameter(SignatureReader reader) { int fistIndex = reader.index; // Search ':' @@ -408,7 +469,7 @@ protected TypeParameter parseTypeParameter(SignatureReader reader) { * Rules: * ThrowsSignature: '^' ClassTypeSignature | '^' TypeVariableSignature */ - protected Type parseExceptionSignature(SignatureReader reader) { + private Type parseExceptionSignature(SignatureReader reader) { if (reader.nextEqualsTo('^')) { // Skip '^' reader.index++; @@ -419,6 +480,106 @@ protected Type parseExceptionSignature(SignatureReader reader) { } } + /** + * Rules: + * ClassTypeSignature: 'L' PackageSpecifier* SimpleClassTypeSignature ClassTypeSignatureSuffix* ';' + * SimpleClassTypeSignature: Identifier TypeArguments? + * ClassTypeSignatureSuffix: '.' SimpleClassTypeSignature + */ + private ObjectType parseClassTypeSignature(SignatureReader reader, int dimension) { + if (reader.nextEqualsTo('L')) { + // Skip 'L'. Parse 'PackageSpecifier* SimpleClassTypeSignature' + int index = ++reader.index; + char endMarker = reader.searchEndMarker(); + + if (endMarker == 0) { + throw new SignatureFormatException(reader.signature); + } + + String internalTypeName = reader.substring(index); + ObjectType ot = makeFromInternalTypeName(internalTypeName); + + if (endMarker == '<') { + // Skip '<' + reader.index++; + ot = ot.createType(parseTypeArguments(reader)); + if (reader.read() != '>') + throw new SignatureFormatException(reader.signature); + } + + // Parse 'ClassTypeSignatureSuffix*' + while (reader.nextEqualsTo('.')) { + // Skip '.' + index = ++reader.index; + endMarker = reader.searchEndMarker(); + + if (endMarker == 0) { + throw new SignatureFormatException(reader.signature); + } + + String name = reader.substring(index); + internalTypeName += '$' + name; + String qualifiedName; + + if (Character.isDigit(name.charAt(0))) { + name = extractLocalClassName(name); + qualifiedName = null; + } else { + qualifiedName = ot.getQualifiedName() + '.' + name; + } + + if (endMarker == '<') { + // Skip '<' + reader.index++; + + BaseTypeArgument typeArguments = parseTypeArguments(reader); + if (reader.read() != '>') { + throw new SignatureFormatException(reader.signature); + } + + ot = new InnerObjectType(internalTypeName, qualifiedName, name, typeArguments, ot); + } else { + ot = new InnerObjectType(internalTypeName, qualifiedName, name, ot); + } + } + + // Skip ';' + reader.index++; + + return (dimension==0) ? ot : (ObjectType)ot.createType(dimension); + } else { + return null; + } + } + + /** + * Rules: + * TypeArguments: '<' TypeArgument+ '>' + */ + private BaseTypeArgument parseTypeArguments(SignatureReader reader) { + TypeArgument firstTypeArgument = parseTypeArgument(reader); + + if (firstTypeArgument == null) { + throw new SignatureFormatException(reader.signature); + } + + TypeArgument nextTypeArgument = parseTypeArgument(reader); + + if (nextTypeArgument == null) { + return firstTypeArgument; + } else { + ArrayTypeArguments typeArguments = new ArrayTypeArguments(); + typeArguments.add(firstTypeArgument); + + do { + typeArguments.add(nextTypeArgument); + nextTypeArgument = parseTypeArgument(reader); + } while (nextTypeArgument != null); + + return typeArguments; + } + } + /** * Rules: * ReferenceTypeSignature: ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature @@ -428,7 +589,7 @@ protected Type parseExceptionSignature(SignatureReader reader) { * BaseType: 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' * TypeVariableSignature: 'T' Identifier ';' */ - protected Type parseReferenceTypeSignature(SignatureReader reader) { + private Type parseReferenceTypeSignature(SignatureReader reader) { if (reader.available()) { int dimension = 0; char c = reader.read(); @@ -484,7 +645,27 @@ protected Type parseReferenceTypeSignature(SignatureReader reader) { } } - protected boolean isAReferenceTypeSignature(SignatureReader reader) { + /** + * Rules: + * TypeArgument: WildcardIndicator? FieldTypeSignature | '*' + * WildcardIndicator: '+' | '-' + */ + private TypeArgument parseTypeArgument(SignatureReader reader) { + switch (reader.read()) { + case '+': + return new WildcardExtendsTypeArgument(parseReferenceTypeSignature(reader)); + case '-': + return new WildcardSuperTypeArgument(parseReferenceTypeSignature(reader)); + case '*': + return WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; + default: + // Unread 'c' + reader.index--; + return parseReferenceTypeSignature(reader); + } + } + + private static boolean isAReferenceTypeSignature(SignatureReader reader) { if (reader.available()) { // Skip dimension char c = reader.read(); @@ -517,79 +698,7 @@ protected boolean isAReferenceTypeSignature(SignatureReader reader) { } } - /** - * Rules: - * ClassTypeSignature: 'L' PackageSpecifier* SimpleClassTypeSignature ClassTypeSignatureSuffix* ';' - * SimpleClassTypeSignature: Identifier TypeArguments? - * ClassTypeSignatureSuffix: '.' SimpleClassTypeSignature - */ - protected ObjectType parseClassTypeSignature(SignatureReader reader, int dimension) { - if (reader.nextEqualsTo('L')) { - // Skip 'L'. Parse 'PackageSpecifier* SimpleClassTypeSignature' - int index = ++reader.index; - char endMarker = reader.searchEndMarker(); - - if (endMarker == 0) { - throw new SignatureFormatException(reader.signature); - } - - String internalTypeName = reader.substring(index); - ObjectType ot = makeFromInternalTypeName(internalTypeName); - - if (endMarker == '<') { - // Skip '<' - reader.index++; - ot = ot.createType(parseTypeArguments(reader)); - if (reader.read() != '>') - throw new SignatureFormatException(reader.signature); - } - - // Parse 'ClassTypeSignatureSuffix*' - while (reader.nextEqualsTo('.')) { - // Skip '.' - index = ++reader.index; - endMarker = reader.searchEndMarker(); - - if (endMarker == 0) { - throw new SignatureFormatException(reader.signature); - } - - String name = reader.substring(index); - internalTypeName += '$' + name; - String qualifiedName; - - if (Character.isDigit(name.charAt(0))) { - name = extractLocalClassName(name); - qualifiedName = null; - } else { - qualifiedName = ot.getQualifiedName() + '.' + name; - } - - if (endMarker == '<') { - // Skip '<' - reader.index++; - - BaseTypeArgument typeArguments = parseTypeArguments(reader); - if (reader.read() != '>') { - throw new SignatureFormatException(reader.signature); - } - - ot = new InnerObjectType(internalTypeName, qualifiedName, name, typeArguments, ot); - } else { - ot = new InnerObjectType(internalTypeName, qualifiedName, name, ot); - } - } - - // Skip ';' - reader.index++; - - return (dimension==0) ? ot : (ObjectType)ot.createType(dimension); - } else { - return null; - } - } - - protected boolean isAClassTypeSignature(SignatureReader reader) { + private static boolean isAClassTypeSignature(SignatureReader reader) { if (reader.nextEqualsTo('L')) { // Skip 'L' reader.index++; @@ -636,35 +745,7 @@ protected boolean isAClassTypeSignature(SignatureReader reader) { } } - /** - * Rules: - * TypeArguments: '<' TypeArgument+ '>' - */ - protected BaseTypeArgument parseTypeArguments(SignatureReader reader) { - TypeArgument firstTypeArgument = parseTypeArgument(reader); - - if (firstTypeArgument == null) { - throw new SignatureFormatException(reader.signature); - } - - TypeArgument nextTypeArgument = parseTypeArgument(reader); - - if (nextTypeArgument == null) { - return firstTypeArgument; - } else { - ArrayTypeArguments typeArguments = new ArrayTypeArguments(); - typeArguments.add(firstTypeArgument); - - do { - typeArguments.add(nextTypeArgument); - nextTypeArgument = parseTypeArgument(reader); - } while (nextTypeArgument != null); - - return typeArguments; - } - } - - protected boolean isATypeArguments(SignatureReader reader) { + private static boolean isATypeArguments(SignatureReader reader) { if (isATypeArgument(reader) == false) throw new SignatureFormatException(reader.signature); @@ -673,27 +754,7 @@ protected boolean isATypeArguments(SignatureReader reader) { return true; } - /** - * Rules: - * TypeArgument: WildcardIndicator? FieldTypeSignature | '*' - * WildcardIndicator: '+' | '-' - */ - protected TypeArgument parseTypeArgument(SignatureReader reader) { - switch (reader.read()) { - case '+': - return new WildcardExtendsTypeArgument(parseReferenceTypeSignature(reader)); - case '-': - return new WildcardSuperTypeArgument(parseReferenceTypeSignature(reader)); - case '*': - return WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; - default: - // Unread 'c' - reader.index--; - return parseReferenceTypeSignature(reader); - } - } - - protected boolean isATypeArgument(SignatureReader reader) { + private static boolean isATypeArgument(SignatureReader reader) { switch (reader.read()) { case '+': case '-': return isAReferenceTypeSignature(reader); @@ -706,7 +767,7 @@ protected boolean isATypeArgument(SignatureReader reader) { } } - protected static String extractLocalClassName(String name) { + private static String extractLocalClassName(String name) { if (Character.isDigit(name.charAt(0))) { int i = 0, len = name.length(); @@ -720,119 +781,10 @@ protected static String extractLocalClassName(String name) { return name; } - private final static class SignatureReader { - public String signature; - public char[] array; - public int length; - public int index = 0; - - public SignatureReader(String signature) { - this(signature, 0); - } - - public SignatureReader(String signature, int index) { - this.signature = signature; - this.array = signature.toCharArray(); - this.length = array.length; - this.index = index; - } - - public char read() { - return array[index++]; - } - - public boolean nextEqualsTo(char c) { - return (index < length) && (array[index] == c); - } - - public boolean search(char c) { - int length = array.length; - - for (int i=index; i parameterTypes; - public Type returnedType; - public BaseType exceptions; - } - - protected static final HashMap INTERNALNAME_TO_OBJECTTYPE = new HashMap<>(); - protected static final HashMap INTERNALNAME_TO_OBJECTPRIMITIVETYPE = new HashMap<>(); - - static { - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_CLASS.getInternalName(), ObjectType.TYPE_CLASS); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_OBJECT.getInternalName(), ObjectType.TYPE_OBJECT); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_STRING.getInternalName(), ObjectType.TYPE_STRING); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_THROWABLE.getInternalName(), ObjectType.TYPE_THROWABLE); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_EXCEPTION.getInternalName(), ObjectType.TYPE_EXCEPTION); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_RUNTIME_EXCEPTION.getInternalName(), ObjectType.TYPE_RUNTIME_EXCEPTION); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_SYSTEM.getInternalName(), ObjectType.TYPE_SYSTEM); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_STRING_BUILDER.getInternalName(), ObjectType.TYPE_STRING_BUILDER); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_STRING_BUFFER.getInternalName(), ObjectType.TYPE_STRING_BUFFER); - INTERNALNAME_TO_OBJECTTYPE.put(ObjectType.TYPE_THREAD.getInternalName(), ObjectType.TYPE_THREAD); - - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_BOOLEAN.getInternalName(), ObjectType.TYPE_PRIMITIVE_BOOLEAN); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_BYTE.getInternalName(), ObjectType.TYPE_PRIMITIVE_BYTE); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_CHAR.getInternalName(), ObjectType.TYPE_PRIMITIVE_CHAR); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_DOUBLE.getInternalName(), ObjectType.TYPE_PRIMITIVE_DOUBLE); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_FLOAT.getInternalName(), ObjectType.TYPE_PRIMITIVE_FLOAT); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_INT.getInternalName(), ObjectType.TYPE_PRIMITIVE_INT); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_LONG.getInternalName(), ObjectType.TYPE_PRIMITIVE_LONG); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_SHORT.getInternalName(), ObjectType.TYPE_PRIMITIVE_SHORT); - INTERNALNAME_TO_OBJECTPRIMITIVETYPE.put(ObjectType.TYPE_PRIMITIVE_VOID.getInternalName(), ObjectType.TYPE_PRIMITIVE_VOID); + public ObjectType makeFromDescriptorOrInternalTypeName(String descriptorOrInternalTypeName) { + return (descriptorOrInternalTypeName.charAt(0) == '[') ? makeFromDescriptor(descriptorOrInternalTypeName) : makeFromInternalTypeName(descriptorOrInternalTypeName); } - protected HashMap descriptorToObjectType = new HashMap<>(1024); - protected HashMap internalTypeNameToObjectType = new HashMap<>(1024); - protected HashMap hierarchy = new HashMap<>(1024); - protected Loader loader; - public ObjectType makeFromDescriptor(String descriptor) { ObjectType ot = descriptorToObjectType.get(descriptor); @@ -868,109 +820,11 @@ private ObjectType makeFromDescriptorWithoutBracket(String descriptor) { public ObjectType makeFromInternalTypeName(String internalTypeName) { assert (internalTypeName != null) && !internalTypeName.endsWith(";") : "ObjectTypeMaker.makeFromInternalTypeName(internalTypeName) : invalid internalTypeName"; - ObjectType ot = INTERNALNAME_TO_OBJECTTYPE.get(internalTypeName); - - if (ot == null) { - ot = internalTypeNameToObjectType.get(internalTypeName); - } - - if (ot == null) { - // Search class file with loader, first - ot = loadFromLoader(internalTypeName); - - if (ot == null) { - // File not found with the loader -> Try to load class with system class loader - ot = loadFromClassLoader(internalTypeName); - } - - if (ot == null) { - // File not found with the system class loader -> Create type just from 'internalTypeName' - ot = create(internalTypeName); - } - } - - return ot; - } - - public ObjectType makeFromDescriptorOrInternalTypeName(String descriptorOrInternalTypeName) { - return (descriptorOrInternalTypeName.charAt(0) == '[') ? makeFromDescriptor(descriptorOrInternalTypeName) : makeFromInternalTypeName(descriptorOrInternalTypeName); - } - - private ObjectType loadFromLoader(String internalTypeName) { - try { - ObjectType ot = internalTypeNameToObjectType.get(internalTypeName); - - if ((ot == null) && loader.canLoad(internalTypeName)) { - String outerTypeName = getOuterTypeName(internalTypeName); - - if (outerTypeName == null) { - int lastSlash = internalTypeName.lastIndexOf('/'); - String qualifiedName = internalTypeName.replace('/', '.'); - String name = qualifiedName.substring(lastSlash + 1); - - ot = new ObjectType(internalTypeName, qualifiedName, name); - } else { - ObjectType outerOT = loadFromLoader(outerTypeName); - int index; - - assert outerOT != null; - - if (internalTypeName.length() > outerTypeName.length() + 1) { - index = outerTypeName.length(); - } else { - index = internalTypeName.lastIndexOf('$'); - } - - String innerName = internalTypeName.substring(index + 1); - - if (Character.isDigit(innerName.charAt(0))) { - ot = new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerOT); - } else { - String qualifiedName = outerOT.getQualifiedName() + '.' + innerName; - ot = new InnerObjectType(internalTypeName, qualifiedName, innerName, outerOT); - } - } - - internalTypeNameToObjectType.put(internalTypeName, ot); - } - - return ot; - } catch (Exception ignore) { - // Class file not found by the system class loader, or invalid class file - return null; - } - } - - private ObjectType loadFromClassLoader(String internalTypeName) { - ObjectType ot = internalTypeNameToObjectType.get(internalTypeName); + ObjectType ot = loadType(internalTypeName); if (ot == null) { - try { - Class clazz = getClass().getClassLoader().loadClass(internalTypeName.replace('/', '.')); - String qualifiedName = clazz.getCanonicalName(); - String name = clazz.getSimpleName(); - - if (clazz.isMemberClass()) { - String outerInternalTypeName; - - if (name.isEmpty()) { - // Anonymous type - outerInternalTypeName = internalTypeName.substring(0, internalTypeName.lastIndexOf('$')); - } else { - // Inner type - outerInternalTypeName = internalTypeName.substring(0, internalTypeName.length()-name.length()-1); - } - - ObjectType outerSot = loadFromClassLoader(outerInternalTypeName); - - ot = new InnerObjectType(internalTypeName, qualifiedName, name, outerSot); - } else { - ot = new ObjectType(internalTypeName, qualifiedName, name); - } - } catch (ClassNotFoundException ignore) { - } - - internalTypeNameToObjectType.put(internalTypeName, ot); + // File not found with the system class loader -> Create type from 'internalTypeName' + ot = create(internalTypeName); } return ot; @@ -1016,8 +870,9 @@ public boolean isAssignable(ObjectType parent, ObjectType child) { String parentInternalName = parent.getInternalName(); String childInternalName = child.getInternalName(); - if (parentInternalName.equals(childInternalName) || parentInternalName.equals("java/lang/Object")) + if (parentInternalName.equals(childInternalName) || parentInternalName.equals("java/lang/Object")) { return true; + } return recursiveIsAssignable(parentInternalName, childInternalName); } @@ -1031,18 +886,8 @@ private boolean recursiveIsAssignable(String parentInternalName, String childInt String[] superClassAndInterfaceNames = hierarchy.get(childInternalName); if (superClassAndInterfaceNames == null) { - try { - if (loader.canLoad(childInternalName)) { - loadFromLoader(childInternalName); - superClassAndInterfaceNames = hierarchy.get(childInternalName); - } else { - Class childClazz = getClass().getClassLoader().loadClass(childInternalName.replace('/', '.')); - Class parentClazz = getClass().getClassLoader().loadClass(parentInternalName.replace('/', '.')); - return parentClazz.isAssignableFrom(childClazz); - } - } catch (Exception ignore) { - return false; - } + loadType(childInternalName); + superClassAndInterfaceNames = hierarchy.get(childInternalName); } if (superClassAndInterfaceNames != null) { @@ -1060,150 +905,377 @@ private boolean recursiveIsAssignable(String parentInternalName, String childInt return false; } - private String getOuterTypeName(String internalTypeName) throws Exception { - return loadTypeAndApplyFunction(internalTypeName, null, searchOuterTypeName); - } + public BaseTypeParameter makeTypeParameters(ObjectType objectType) { + String internalTypeName = objectType.getInternalName(); + + if (internalTypeNameToTypeParameters.containsKey(internalTypeName)) { + return internalTypeNameToTypeParameters.get(internalTypeName); + } - private Object[] constants = new Object[1000]; + BaseTypeParameter typeParameters = null; + + try { + if (loader.canLoad(internalTypeName)) { + internalTypeNameToTypeParameters.put(internalTypeName, typeParameters = loadTypeParameters(internalTypeName, loader.load(internalTypeName))); + } else if (classPathLoader.canLoad(internalTypeName)) { + internalTypeNameToTypeParameters.put(internalTypeName, typeParameters = loadTypeParameters(internalTypeName, classPathLoader.load(internalTypeName))); + } + } catch (Exception e) { + assert ExceptionUtil.printStackTrace(e); + } - @FunctionalInterface - private interface Function { - String apply(ClassFileReader reader, String typeName, String innerTypeName) throws Exception; + return typeParameters; } - private Function checkInnerTypeName = (reader, typeName, innerTypeName) -> { - int count = reader.readUnsignedShort(); + private BaseTypeParameter loadTypeParameters(String internalTypeName, byte[] data) throws Exception { + if (data == null) { + return null; + } - for(int i=0; i < count; i++) { - int innerTypeIndex = reader.readUnsignedShort(); + ClassFileReader reader = new ClassFileReader(data); + Object[] constants = loadClassFile(internalTypeName, reader); - // Skip 'outerTypeIndex', 'innerNameIndex' & innerAccessFlags' - reader.skip(3 * 2); + // Skip fields + skipMembers(reader); - ConstantClass cc = (ConstantClass)constants[innerTypeIndex]; - String innerInternalTypeName = (String)constants[cc.getNameIndex()]; + // Skip methods + skipMembers(reader); - if (innerTypeName.equals(innerInternalTypeName)) { - return typeName; + String outerTypeName = null; + ObjectType outerObjectType = null; + + // Load attributes + String signature = null; + int count = reader.readUnsignedShort(); + + for (int j=0; j { - int count = reader.readUnsignedShort(); + SignatureReader signatureReader = new SignatureReader(signature); + return parseTypeParameters(signatureReader); + } - for(int i=0; i < count; i++) { - int innerTypeIndex = reader.readUnsignedShort(); - int outerTypeIndex = reader.readUnsignedShort(); + public Type makeFieldType(ObjectType objectType, String fieldName, String descriptor) { + String internalTypeName = objectType.getInternalName(); + String key = internalTypeName + ':' + fieldName; + Type type = internalTypeNameFieldNameToType.get(key); - // Skip 'innerNameIndex' & innerAccessFlags' - reader.skip(2 * 2); + if (type == null) { + // Load fields + if (loadFieldsAndMethods(internalTypeName)) { + type = internalTypeNameFieldNameToType.get(key); + if (type == null) { + internalTypeNameFieldNameToType.put(key, type = makeFromSignature(descriptor)); + } + } else { + internalTypeNameFieldNameToType.put(key, type = makeFromSignature(descriptor)); + } + } - ConstantClass cc = (ConstantClass)constants[innerTypeIndex]; - innerTypeName = (String)constants[cc.getNameIndex()]; + return type; + } - if (innerTypeName.equals(typeName)) { - if (outerTypeIndex == 0) { - // Synthetic inner class -> Search outer class - int lastDollar = typeName.lastIndexOf('$'); + public MethodTypes makeMethodTypes(String descriptor) { + return parseMethodSignature(descriptor, null); + } - if (lastDollar != -1) { - String outerTypeName = typeName.substring(0, lastDollar); - return loadTypeAndApplyFunction(outerTypeName, typeName, checkInnerTypeName); - } + public MethodTypes makeMethodTypes(ObjectType objectType, String methodName, String descriptor) { + String internalTypeName = objectType.getInternalName(); + String key = internalTypeName + ':' + methodName + descriptor; + MethodTypes methodTypes = internalTypeNameMethodNameDescriptorToMethodTypes.get(key); - return null; - } else { - // Return 'outerTypeName' - cc = (ConstantClass)constants[outerTypeIndex]; - return (String)constants[cc.getNameIndex()]; + if (methodTypes == null) { + // Load method + if (loadFieldsAndMethods(internalTypeName)) { + methodTypes = internalTypeNameMethodNameDescriptorToMethodTypes.get(key); + if (methodTypes == null) { + internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes = parseMethodSignature(descriptor, null)); } + } else { + internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes = parseMethodSignature(descriptor, null)); } } - return null; - }; + return methodTypes; + } + + private ObjectType loadType(String internalTypeName) { + ObjectType ot = internalTypeNameToObjectType.get(internalTypeName); + + if (ot == null) { + try { + if (loader.canLoad(internalTypeName)) { + internalTypeNameToObjectType.put(internalTypeName, ot = loadType(internalTypeName, loader.load(internalTypeName))); + } else if (classPathLoader.canLoad(internalTypeName)) { + internalTypeNameToObjectType.put(internalTypeName, ot = loadType(internalTypeName, classPathLoader.load(internalTypeName))); + } + } catch (Exception e) { + assert ExceptionUtil.printStackTrace(e); + } + } - private String loadTypeAndApplyFunction(String typeName, String innerTypeName, Function function) throws Exception { - byte[] data = loader.load(typeName); + return ot; + } + private ObjectType loadType(String internalTypeName, byte[] data) throws Exception { if (data == null) { return null; - } else { - ClassFileReader reader = new ClassFileReader(data); + } - int magic = reader.readInt(); + ClassFileReader reader = new ClassFileReader(data); + Object[] constants = loadClassFile(internalTypeName, reader); - if (magic != ClassFileReader.JAVA_MAGIC_NUMBER) - throw new ClassFileFormatException("Invalid CLASS file"); + // Skip fields + skipMembers(reader); - // Skip 'minorVersion', 'majorVersion' - reader.skip(2 * 2); + // Skip methods + skipMembers(reader); - Object[] constants = loadConstants(reader); + String outerTypeName = null; + ObjectType outerObjectType = null; - // Skip 'accessFlags' & 'thisClassIndex' - reader.skip(2 * 2); + // Load attributes + int count = reader.readUnsignedShort(); + for (int i = 0; i < count; i++) { + int attributeNameIndex = reader.readUnsignedShort(); + int attributeLength = reader.readInt(); + + if ("InnerClasses".equals(constants[attributeNameIndex])) { + int innerClassesCount = reader.readUnsignedShort(); + + for(int j=0; j < innerClassesCount; j++) { + int innerTypeIndex = reader.readUnsignedShort(); + int outerTypeIndex = reader.readUnsignedShort(); - // Load super class name - int superClassIndex = reader.readUnsignedShort(); - String superClassName; + // Skip 'innerNameIndex' & innerAccessFlags' + reader.skip(2 * 2); - if (superClassIndex == 0) { - superClassName = null; + Integer cc = (Integer)constants[innerTypeIndex]; + String innerTypeName = (String)constants[cc.intValue()]; + + if (innerTypeName.equals(internalTypeName)) { + if (outerTypeIndex == 0) { + // Synthetic inner class -> Search outer class + int lastDollar = internalTypeName.lastIndexOf('$'); + + if (lastDollar != -1) { + outerTypeName = internalTypeName.substring(0, lastDollar); + outerObjectType = loadType(outerTypeName); + } + } else { + // Return 'outerTypeName' + cc = (Integer)constants[outerTypeIndex]; + outerTypeName = (String)constants[cc.intValue()]; + outerObjectType = loadType(outerTypeName); + } + break; + } + } + + break; } else { - ConstantClass cc = (ConstantClass)constants[superClassIndex]; - superClassName = (String)constants[cc.getNameIndex()]; + reader.skip(attributeLength); } + } - // Load interface blackListNames - int count = reader.readUnsignedShort(); - String[] superClassAndInterfaceNames = new String[count + 1]; + if (outerObjectType == null) { + int lastSlash = internalTypeName.lastIndexOf('/'); + String qualifiedName = internalTypeName.replace('/', '.'); + String name = qualifiedName.substring(lastSlash + 1); - superClassAndInterfaceNames[0] = superClassName; + return new ObjectType(internalTypeName, qualifiedName, name); + } else { + int index; - for (int i = 1; i <= count; i++) { - int interfaceIndex = reader.readUnsignedShort(); - ConstantClass cc = (ConstantClass)constants[interfaceIndex]; - superClassAndInterfaceNames[i] = (String)constants[cc.getNameIndex()]; + if (internalTypeName.length() > outerTypeName.length() + 1) { + index = outerTypeName.length(); + } else { + index = internalTypeName.lastIndexOf('$'); } - hierarchy.put(typeName, superClassAndInterfaceNames); + String innerName = internalTypeName.substring(index + 1); - // Skip fields - count = reader.readUnsignedShort(); - for (int i = 0; i < count; i++) { - // skip 'accessFlags', 'nameIndex', 'signatureIndex' - reader.skip(3 * 2); - skipAttributes(reader); + if (Character.isDigit(innerName.charAt(0))) { + return new InnerObjectType(internalTypeName, null, extractLocalClassName(innerName), outerObjectType); + } else { + String qualifiedName = outerObjectType.getQualifiedName() + '.' + innerName; + return new InnerObjectType(internalTypeName, qualifiedName, innerName, outerObjectType); } + } + } - // Skip methods - count = reader.readUnsignedShort(); + private boolean loadFieldsAndMethods(String internalTypeName) { + try { + if (loader.canLoad(internalTypeName)) { + loadFieldsAndMethods(internalTypeName, loader.load(internalTypeName)); + return true; + } else if (classPathLoader.canLoad(internalTypeName)) { + loadFieldsAndMethods(internalTypeName, classPathLoader.load(internalTypeName)); + return true; + } + } catch (Exception e) { + assert ExceptionUtil.printStackTrace(e); + } + + return false; + } + + private void loadFieldsAndMethods(String internalTypeName, byte[] data) throws Exception { + if (data != null) { + ClassFileReader reader = new ClassFileReader(data); + Object[] constants = loadClassFile(internalTypeName, reader); + + // Load fields + int count = reader.readUnsignedShort(); for (int i = 0; i < count; i++) { - // skip 'accessFlags', 'nameIndex', 'signatureIndex' - reader.skip(3 * 2); - skipAttributes(reader); + // skip 'accessFlags' + reader.skip(2); + + int nameIndex = reader.readUnsignedShort(); + int descriptorIndex = reader.readUnsignedShort(); + + // Load attributes + String signature = null; + int attributeCount = reader.readUnsignedShort(); + + for (int j=0; j 0) { + exceptionTypeNames = new String[exceptionCount]; + + for (int k=0; k 0) { + out.write(buffer, 0, read); + read = in.read(buffer); } + + return out.toByteArray(); + } catch (IOException e) { + throw new LoaderException(e); } - } else { - // Search method - // ... } } - return parseMethodSignature(descriptor, null); + @Override + public boolean canLoad(String internalName) { + return this.getClass().getResource("/" + internalName + ".class") != null; + } } - public Type makeFieldType(ObjectType objectType, String fieldName, String descriptor) { - if (objectType.getDimension() == 0) { - String key = objectType.getInternalName() + ':' + fieldName; + private static class SignatureReader { + public String signature; + public char[] array; + public int length; + public int index = 0; + + public SignatureReader(String signature) { + this(signature, 0); + } + + public SignatureReader(String signature, int index) { + this.signature = signature; + this.array = signature.toCharArray(); + this.length = array.length; + this.index = index; + } + + public char read() { + return array[index++]; + } + + public boolean nextEqualsTo(char c) { + return (index < length) && (array[index] == c); + } - if (internalTypeNameFieldNameToType.containsKey(key)) { - Type type = internalTypeNameFieldNameToType.get(key); + public boolean search(char c) { + int length = array.length; - if (type != null) { - return type; + for (int i=index; i 0) { + t = t.createType(t.getDimension() + extraDimension); + } + + declaration.setExpression(updateExpression(t, expression)); + } + + @Override + public void visit(SuperConstructorInvocationExpression expression) { + BaseExpression parameters = expression.getParameters(); + + if (parameters != null) { + expression.setParameters(updateExpressions(((ClassFileSuperConstructorInvocationExpression)expression).getParameterTypes(), parameters)); + } + } + + @Override + public void visit(ConstructorInvocationExpression expression) { + BaseExpression parameters = expression.getParameters(); + + if (parameters != null) { + expression.setParameters(updateExpressions(((ClassFileConstructorInvocationExpression)expression).getParameterTypes(), parameters)); + } + } + + @Override + public void visit(MethodInvocationExpression expression) { + BaseExpression parameters = expression.getParameters(); + + if (parameters != null) { + ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; + + if (mie.getTypeParameters() == null) { + // Do not add cast expression if method contains type parameters + expression.setParameters(updateExpressions(mie.getParameterTypes(), parameters)); + } else { + parameters.accept(this); + } + } + + expression.getExpression().accept(this); + } + + @Override + public void visit(NewExpression expression) { + BaseExpression parameters = expression.getParameters(); + + if (parameters != null) { + expression.setParameters(updateExpressions(((ClassFileNewExpression)expression).getParameterTypes(), parameters)); + } + } + + @Override + public void visit(NewInitializedArray expression) { + ArrayVariableInitializer arrayInitializer = expression.getArrayInitializer(); + + if (arrayInitializer != null) { + Type t = type; + + type = expression.getType(); + type = type.createType(type.getDimension() - 1); + arrayInitializer.accept(this); + type = t; + } + } + + @Override + public void visit(BinaryOperatorExpression expression) { + expression.getLeftExpression().accept(this); + + Expression rightExpression = expression.getRightExpression(); + + if (expression.getOperator().equals("=")) { + if (rightExpression.getClass() == ClassFileMethodInvocationExpression.class) { + ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)rightExpression; + + if (mie.getTypeParameters() != null) { + // Do not add cast expression if method contains type parameters + rightExpression.accept(this); + return; + } + } + + expression.setRightExpression(updateExpression(expression.getLeftExpression().getType(), rightExpression)); + return; + } + + rightExpression.accept(this); + } + + @SuppressWarnings("unchecked") + protected BaseExpression updateExpressions(BaseType types, BaseExpression expressions) { + if (expressions != null) { + if (expressions.isList()) { + DefaultList t = types.getList(); + DefaultList e = expressions.getList(); + + for (int i = e.size() - 1; i >= 0; i--) { + e.set(i, updateExpression(t.get(i), e.get(i))); + } + } else { + expressions = updateExpression(types.getFirst(), (Expression) expressions); + } + } + + return expressions; + } + + private Expression updateExpression(Type type, Expression expression) { + Class expressionClass = expression.getClass(); + + if (expressionClass != NullExpression.class) { + Type expressionType = expression.getType(); + + if (!expressionType.equals(type) && !TYPE_OBJECT.equals(type)) { + if (type.isObject()) { + if (expressionType.isObject()) { + ObjectType objectType = (ObjectType) type; + ObjectType expressionObjectType = (ObjectType) expressionType; + String internalName = objectType.getInternalName(); + + if (internalName.equals(expressionObjectType.getInternalName()) || typeMaker.isAssignable(objectType, expressionObjectType)) { + if (!internalName.equals(TYPE_CLASS.getInternalName())) { + if (expressionObjectType.getTypeArguments() != null) { + if ((objectType.getTypeArguments() == null) || !objectType.getTypeArguments().isTypeArgumentAssignableFrom(expressionObjectType.getTypeArguments())) { + expression = addCastExpression(type, expression); + } + } + } + } + } + } else if (type.isGeneric()) { + if (expressionType.isObject()) { + expression = addCastExpression(type, expression); + } + } + } + } + + expression.accept(this); + + return expression; + } + + private static final Expression addCastExpression(Type type, Expression expression) { + if (expression.getClass() == CastExpression.class) { + ((CastExpression)expression).setType(type); + return expression; + } else { + return new CastExpression(expression.getLineNumber(), type, expression); + } + } + + @Override public void visit(FloatConstantExpression expression) {} + @Override public void visit(IntegerConstantExpression expression) {} + @Override public void visit(ConstructorReferenceExpression expression) {} + @Override public void visit(DoubleConstantExpression expression) {} + @Override public void visit(EnumConstantReferenceExpression expression) {} + @Override public void visit(LocalVariableReferenceExpression expression) {} + @Override public void visit(LongConstantExpression expression) {} + @Override public void visit(BreakStatement statement) {} + @Override public void visit(ByteCodeStatement statement) {} + @Override public void visit(ContinueStatement statement) {} + @Override public void visit(NullExpression expression) {} + @Override public void visit(ObjectTypeReferenceExpression expression) {} + @Override public void visit(SuperExpression expression) {} + @Override public void visit(ThisExpression expression) {} + @Override public void visit(TypeReferenceDotClassExpression expression) {} + @Override public void visit(ObjectReference reference) {} + @Override public void visit(InnerObjectReference reference) {} + @Override public void visit(ArrayTypeArguments type) {} + @Override public void visit(WildcardExtendsTypeArgument type) {} + @Override public void visit(ObjectType type) {} + @Override public void visit(InnerObjectType type) {} + @Override public void visit(WildcardSuperTypeArgument type) {} + @Override public void visit(Types list) {} + @Override public void visit(TypeBounds list) {} + @Override public void visit(TypeParameterWithTypeBounds type) {} +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java index cc648ed4..18de297b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java @@ -53,8 +53,18 @@ public void visit(BodyDeclaration declaration) { method.accept(this); } } else if (method.getParameterTypes() != null) { - for (Type type : method.getParameterTypes()) { - if (type.isObject() && ((ObjectType)type).getName() == null) { + if (method.getParameterTypes().isList()) { + for (Type type : method.getParameterTypes().getList()) { + if (type.isObject() && ((ObjectType) type).getName() == null) { + // Synthetic type in parameterTypes -> synthetic method + method.setFlags(method.getFlags() | FLAG_SYNTHETIC); + method.accept(this); + break; + } + } + } else { + Type type = method.getParameterTypes().getFirst(); + if (type.isObject() && ((ObjectType) type).getName() == null) { // Synthetic type in parameterTypes -> synthetic method method.setFlags(method.getFlags() | FLAG_SYNTHETIC); method.accept(this); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java index e862f9a8..c55abc7a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java @@ -94,6 +94,7 @@ public void visit(FieldDeclarator declaration) { } @Override + @SuppressWarnings("unchecked") public void visit(NewExpression expression) { Expressions parameters = (Expressions)expression.getParameters(); Expression exp = parameters.get(1); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 3695b73f..6ca0fb56 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -13,8 +13,8 @@ import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; @@ -24,6 +24,8 @@ import java.util.*; +import static org.jd.core.v1.model.classfile.Constants.ACC_STATIC; + public class InitInnerClassVisitor extends AbstractJavaSyntaxVisitor { protected UpdateFieldReferencesVisitor updateFieldReferencesVisitor = new UpdateFieldReferencesVisitor(); protected ObjectType outerType; @@ -71,6 +73,8 @@ public void visit(BodyDeclaration declaration) { @SuppressWarnings("unchecked") public void visit(ConstructorDeclaration declaration) { ClassFileConstructorDeclaration cfcd = (ClassFileConstructorDeclaration)declaration; + ClassFile classFile = cfcd.getClassFile(); + ClassFile outerClassFile = classFile.getOuterClassFile(); outerLocalVariableNames.clear(); @@ -87,10 +91,16 @@ public void visit(ConstructorDeclaration declaration) { Class clazz = expression.getClass(); if (clazz == ClassFileSuperConstructorInvocationExpression.class) { + // 'super(...)' break; } if (clazz == ClassFileConstructorInvocationExpression.class) { + // 'this(...)' + if ((outerClassFile != null) && ((classFile.getAccessFlags() & ACC_STATIC) == 0)) { + // Inner non-static class --> First parameter is the synthetic outer reference + outerType = (ObjectType) cfcd.getParameterTypes().getFirst(); + } break; } @@ -140,8 +150,6 @@ public void visit(ConstructorDeclaration declaration) { } // Hide anonymous class constructor - ClassFile outerClassFile = cfcd.getClassFile().getOuterClassFile(); - if (outerClassFile != null) { String outerTypeName = outerClassFile.getInternalTypeName(); String internalTypeName = cfcd.getClassFile().getInternalTypeName(); @@ -176,9 +184,12 @@ public void visit(ConstructorDeclaration declaration) { @Override public void visit(StaticInitializerDeclaration declaration) {} protected class UpdateFieldReferencesVisitor extends AbstractUpdateExpressionVisitor { + protected ClassFileBodyDeclaration bodyDeclaration; + @Override public void visit(BodyDeclaration declaration) { - safeAcceptListDeclaration(((ClassFileBodyDeclaration)declaration).getMethodDeclarations()); + bodyDeclaration = (ClassFileBodyDeclaration)declaration; + safeAcceptListDeclaration(bodyDeclaration.getMethodDeclarations()); } @Override public void visit(StaticInitializerDeclaration declaration) {} @@ -199,10 +210,30 @@ public void visit(NewExpression expression) { @Override public void visit(FieldReferenceExpression expression) { - if (expression.getName().startsWith("this$") && expression.getType().getDescriptor().equals(outerType.getDescriptor())) { - Expression exp = (expression.getExpression() == null) ? expression : expression.getExpression(); - expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), outerType)); - expression.setName("this"); + if (expression.getName().startsWith("this$")) { + if (expression.getType().getDescriptor().equals(outerType.getDescriptor())) { + Expression exp = (expression.getExpression() == null) ? expression : expression.getExpression(); + expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), outerType)); + expression.setName("this"); + } else { + ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(expression.getInternalTypeName()); + + if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { + ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; + + if (cfcd.getInternalTypeName().equals(expression.getInternalTypeName())) { + ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); + String outerInternalTypeName = cfbd.getOuterBodyDeclaration().getInternalTypeName(); + ObjectType objectType = (ObjectType)expression.getType(); + + if (outerInternalTypeName.equals(objectType.getInternalName())) { + Expression exp = (expression.getExpression() == null) ? expression : expression.getExpression(); + expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), objectType)); + expression.setName("this"); + } + } + } + } } else if (outerLocalVariableNames.contains(expression.getName())) { expression.setName(expression.getName().substring(4)); expression.setExpression(null); @@ -414,22 +445,18 @@ public void visit(NewExpression expression) { } } - // Is the last parameter is synthetic ? + // Is the last parameter synthetic ? parameters = expression.getParameters(); - if ((parameters != null) && parameters.isList()) { - DefaultList list = parameters.getList(); - - if (!list.isEmpty()) { - Expression lastParameter = list.getLast(); - - if (lastParameter.getClass() == NullExpression.class) { - DefaultList parameterTypes = ((ClassFileNewExpression) expression).getParameterTypes(); + if ((parameters != null) && (parameters.size() > 0) && (parameters.getLast().getClass() == NullExpression.class)) { + BaseType parameterTypes = ((ClassFileNewExpression) expression).getParameterTypes(); - if (parameterTypes.getLast().getName() == null) { - // Yes. Remove it. - list.removeLast(); - } + if (parameterTypes.getLast().getName() == null) { + // Yes. Remove it. + if (parameters.isList()) { + parameters.getList().removeLast(); + } else { + expression.setParameters(null); } } } @@ -443,6 +470,7 @@ public void visit(SuperConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if ((parameters != null) && (parameters.size() > 0)) { + // Remove outer 'this' reference parameter ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(superTypeName); if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { @@ -453,6 +481,11 @@ public void visit(SuperConstructorInvocationExpression expression) { expression.setParameters(removeOuterThisParameter(parameters)); } } + + // Remove last synthetic parameter + expression.setParameters(removeLastSyntheticParameter( + expression.getParameters(), + ((ClassFileSuperConstructorInvocationExpression)expression).getParameterTypes())); } } @@ -461,14 +494,20 @@ public void visit(ConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if ((parameters != null) && (parameters.size() > 0)) { + // Remove outer this reference parameter if (parameters.getFirst().getType().equals(bodyDeclaration.getOuterType())) { expression.setParameters(removeOuterThisParameter(parameters)); } + + // Remove last synthetic parameter + expression.setParameters(removeLastSyntheticParameter( + expression.getParameters(), + ((ClassFileConstructorInvocationExpression)expression).getParameterTypes())); } } protected BaseExpression removeOuterThisParameter(BaseExpression parameters) { - // Remove outer this + // Remove outer 'this' reference parameter if (parameters.isList()) { parameters.getList().removeFirst(); } else { @@ -478,6 +517,22 @@ protected BaseExpression removeOuterThisParameter(BaseExpression parameters) { return parameters; } + protected BaseExpression removeLastSyntheticParameter(BaseExpression parameters, BaseType parameterTypes) { + // Is the last parameter synthetic ? + if ((parameters != null) && (parameters.size() > 0) && (parameters.getLast().getClass() == NullExpression.class)) { + if (parameterTypes.getLast().getName() == null) { + // Yes. Remove it. + if (parameters.isList()) { + parameters.getList().removeLast(); + } else { + parameters = null; + } + } + } + + return parameters; + } + protected class UpdateFinalFieldReferenceVisitor extends AbstractJavaSyntaxVisitor { protected boolean fina1; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java index 8ae4f068..75509569 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -39,19 +39,19 @@ public void visit(AnnotationDeclaration declaration) { @Override public void visit(ClassDeclaration declaration) { - this.internalTypeName = declaration.getInternalName(); + this.internalTypeName = declaration.getInternalTypeName(); safeAccept(declaration.getBodyDeclaration()); } @Override public void visit(EnumDeclaration declaration) { - this.internalTypeName = declaration.getInternalName(); + this.internalTypeName = declaration.getInternalTypeName(); safeAccept(declaration.getBodyDeclaration()); } @Override public void visit(InterfaceDeclaration declaration) { - this.internalTypeName = declaration.getInternalName(); + this.internalTypeName = declaration.getInternalTypeName(); safeAccept(declaration.getBodyDeclaration()); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java index 9ba81c4f..ce479c7b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java @@ -9,6 +9,7 @@ import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.declaration.*; +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; import org.jd.core.v1.model.javasyntax.expression.Expression; import org.jd.core.v1.model.javasyntax.expression.SuperConstructorInvocationExpression; import org.jd.core.v1.model.javasyntax.statement.ExpressionStatement; @@ -70,8 +71,9 @@ public void visit(ConstructorDeclaration declaration) { if (es.getClass() == ClassFileSuperConstructorInvocationExpression.class) { SuperConstructorInvocationExpression scie = (SuperConstructorInvocationExpression) es; + BaseExpression parameters = scie.getParameters(); - if ("()V".equals(scie.getDescriptor())) { + if ((parameters == null) || (parameters.size() == 0)) { iterator.remove(); break; } @@ -81,28 +83,8 @@ public void visit(ConstructorDeclaration declaration) { // Store empty default constructor if (statements.isEmpty()) { - ClassFileBodyDeclaration bodyDeclaration = cfcd.getBodyDeclaration(); - - if (bodyDeclaration.getOuterLocalVariableNames() == null) { - if (bodyDeclaration.getOuterType() == null) { - if (cfcd.getDescriptor().equals("()V")) { - constructor = cfcd; - } - } else { - if (cfcd.getDescriptor().equals("(L" + bodyDeclaration.getOuterType().getInternalName() + ";)V")) { - constructor = cfcd; - } - } - } else { - int syntheticParameterCount = bodyDeclaration.getOuterLocalVariableNames().size(); - - if (bodyDeclaration.getOuterType() != null) { - syntheticParameterCount++; - } - - if (cfcd.getParameterTypes().size() == syntheticParameterCount) { - constructor = cfcd; - } + if ((cfcd.getFormalParameters() == null) || (cfcd.getFormalParameters().size() == 0)) { + constructor = cfcd; } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchWildcardTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchInTypeArgumentVisitor.java similarity index 69% rename from src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchWildcardTypeArgumentVisitor.java rename to src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchInTypeArgumentVisitor.java index cd3e661c..eb4f60e1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchWildcardTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchInTypeArgumentVisitor.java @@ -7,22 +7,21 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; -import org.jd.core.v1.model.javasyntax.type.AbstractTypeVisitor; -import org.jd.core.v1.model.javasyntax.type.WildcardExtendsTypeArgument; -import org.jd.core.v1.model.javasyntax.type.WildcardSuperTypeArgument; -import org.jd.core.v1.model.javasyntax.type.WildcardTypeArgument; +import org.jd.core.v1.model.javasyntax.type.*; -public class SearchWildcardTypeArgumentVisitor extends AbstractTypeVisitor { +public class SearchInTypeArgumentVisitor extends AbstractTypeVisitor { protected boolean wildcardFound; protected boolean wildcardSuperOrExtendsTypeFound; + protected boolean genericFound; - public SearchWildcardTypeArgumentVisitor() { + public SearchInTypeArgumentVisitor() { init(); } public void init() { wildcardFound = false; wildcardSuperOrExtendsTypeFound = false; + genericFound = false; } public boolean containsWildcard() { @@ -33,6 +32,10 @@ public boolean containsWildcardSuperOrExtendsType() { return wildcardSuperOrExtendsTypeFound; } + public boolean containsGeneric() { + return genericFound; + } + @Override public void visit(WildcardTypeArgument type) { wildcardFound = true; @@ -41,10 +44,17 @@ public void visit(WildcardTypeArgument type) { @Override public void visit(WildcardExtendsTypeArgument type) { wildcardSuperOrExtendsTypeFound = true; + type.getType().accept(this); } @Override public void visit(WildcardSuperTypeArgument type) { wildcardSuperOrExtendsTypeFound = true; + type.getType().accept(this); + } + + @Override + public void visit(GenericType type) { + genericFound = true; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java index b9ac3ab9..34c9221d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -11,8 +11,10 @@ import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.Types; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMethodDeclaration; @@ -41,20 +43,20 @@ protected Expression updateExpression(Expression expression) { return expression; } - MethodInvocationExpression mie1 = (MethodInvocationExpression)expression; + ClassFileMethodInvocationExpression mie1 = (ClassFileMethodInvocationExpression)expression; HashMap map = bridgeMethodDeclarations.get(mie1.getExpression().getType().getDescriptor()); if (map == null) { return expression; } - ClassFileMethodDeclaration methodBridgeDeclaration = map.get(mie1.getName() + mie1.getDescriptor()); + ClassFileMethodDeclaration bridgeMethodDeclaration = map.get(mie1.getName() + mie1.getDescriptor()); - if (methodBridgeDeclaration == null) { + if (bridgeMethodDeclaration == null) { return expression; } - Statement statement = methodBridgeDeclaration.getStatements().getFirst(); + Statement statement = bridgeMethodDeclaration.getStatements().getFirst(); Class statementClass = statement.getClass(); Expression exp; @@ -67,39 +69,25 @@ protected Expression updateExpression(Expression expression) { } Class expClass = exp.getClass(); - - if (expClass == CastExpression.class) { - exp = ((CastExpression)exp).getExpression(); - expClass = exp.getClass(); - } - - int parameterTypesCount = methodBridgeDeclaration.getParameterTypes().size(); + BaseType parameterTypes = bridgeMethodDeclaration.getParameterTypes(); + int parameterTypesCount = (parameterTypes == null) ? 0 : parameterTypes.size(); if (expClass == FieldReferenceExpression.class) { FieldReferenceExpression fre = (FieldReferenceExpression) exp; - if (parameterTypesCount == 0) { - expression = fre.getExpression(); - } else { - expression = mie1.getParameters().getFirst(); - if (expression.getClass() == CastExpression.class) { - CastExpression ce = (CastExpression)expression; - if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { - // Remove cast expression - expression = ce.getExpression(); - } - } - } + expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); return new FieldReferenceExpression(mie1.getLineNumber(), mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()); } else if (expClass == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie2 = (MethodInvocationExpression) exp; if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { - return new MethodInvocationExpression(mie1.getLineNumber(), mie2.getType(), mie2.getExpression(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), mie1.getParameters()); + return new ClassFileMethodInvocationExpression(mie1.getLineNumber(), null, mie2.getType(), mie2.getExpression(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), mie1.getParameterTypes(), mie1.getParameters()); } else { - BaseExpression newParameters = null; + BaseType mie1ParameterTypes = mie1.getParameterTypes(); BaseExpression mie1Parameters = mie1.getParameters(); + BaseType newParameterTypes = null; + BaseExpression newParameters = null; if (mie1Parameters != null) { switch (mie1Parameters.size()) { @@ -107,45 +95,31 @@ protected Expression updateExpression(Expression expression) { case 1: break; case 2: - newParameters = mie1Parameters.getList().get(1); + Expression e = mie1Parameters.getList().get(1); + newParameterTypes = e.getType(); + newParameters = e; break; default: - DefaultList list = mie1Parameters.getList(); - newParameters = new Expressions(list.subList(1, list.size())); + DefaultList t = mie1ParameterTypes.getList(); + newParameterTypes = new Types(t.subList(1, t.size())); + DefaultList p = mie1Parameters.getList(); + newParameters = new Expressions(p.subList(1, p.size())); break; } } - expression = mie1Parameters.getFirst(); - if (expression.getClass() == CastExpression.class) { - CastExpression ce = (CastExpression)expression; - if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { - // Remove cast expression - expression = ce.getExpression(); - } - } - - return new MethodInvocationExpression(mie1.getLineNumber(), mie2.getType(), expression, mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameters); + return new ClassFileMethodInvocationExpression(mie1.getLineNumber(), null, mie2.getType(), mie1Parameters.getFirst(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameterTypes, newParameters); } } else if (expClass == BinaryOperatorExpression.class) { BinaryOperatorExpression boe = (BinaryOperatorExpression) exp; FieldReferenceExpression fre = (FieldReferenceExpression) boe.getLeftExpression(); if (parameterTypesCount == 1) { - expression = mie1.getParameters().getFirst(); - if (expression.getClass() == CastExpression.class) { - CastExpression ce = (CastExpression)expression; - if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { - // Remove cast expression - expression = ce.getExpression(); - } - } - return new BinaryOperatorExpression( mie1.getLineNumber(), mie1.getType(), new FieldReferenceExpression(fre.getType(), fre.getExpression(), fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()), boe.getOperator(), - expression, + mie1.getParameters().getFirst(), boe.getPriority()); } else if (parameterTypesCount == 2) { DefaultList parameters = mie1.getParameters().getList(); @@ -161,18 +135,7 @@ protected Expression updateExpression(Expression expression) { PostOperatorExpression poe = (PostOperatorExpression)exp; FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); - if (parameterTypesCount == 0) { - expression = fre.getExpression(); - } else { - expression = mie1.getParameters().getFirst(); - if (expression.getClass() == CastExpression.class) { - CastExpression ce = (CastExpression)expression; - if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { - // Remove cast expression - expression = ce.getExpression(); - } - } - } + expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); return new PostOperatorExpression( mie1.getLineNumber(), @@ -182,18 +145,7 @@ protected Expression updateExpression(Expression expression) { PreOperatorExpression poe = (PreOperatorExpression)exp; FieldReferenceExpression fre = (FieldReferenceExpression) poe.getExpression(); - if (parameterTypesCount == 0) { - expression = fre.getExpression(); - } else { - expression = mie1.getParameters().getFirst(); - if (expression.getClass() == CastExpression.class) { - CastExpression ce = (CastExpression)expression; - if (ce.getType().getDescriptor().equals(ce.getExpression().getType().getDescriptor())) { - // Remove cast expression - expression = ce.getExpression(); - } - } - } + expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); return new PreOperatorExpression( mie1.getLineNumber(), @@ -280,13 +232,8 @@ private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMe } Class expClass = exp.getClass(); - - if (expClass == CastExpression.class) { - exp = ((CastExpression)exp).getExpression(); - expClass = exp.getClass(); - } - - int parameterTypesCount = bridgeMethodDeclaration.getParameterTypes().size(); + BaseType parameterTypes = bridgeMethodDeclaration.getParameterTypes(); + int parameterTypesCount = (parameterTypes == null) ? 0 : parameterTypes.size(); if (expClass == FieldReferenceExpression.class) { FieldReferenceExpression fre = (FieldReferenceExpression) exp; @@ -392,10 +339,6 @@ private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMe } private boolean checkLocalVariableReference(BaseExpression expression, int index) { - if (expression.getClass() == CastExpression.class) { - expression = ((CastExpression)expression).getExpression(); - } - if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { return false; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 217404a9..8a84d2dd 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -21,16 +21,12 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import org.jd.core.v1.util.DefaultList; -import java.util.AbstractList; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; - public class UpdateIntegerConstantTypeVisitor extends AbstractJavaSyntaxVisitor { - protected static final HashMap> TYPES = new HashMap<>(); + protected static final HashMap TYPES = new HashMap<>(); protected static final DimensionTypes DIMENSION_TYPES = new DimensionTypes(); @@ -42,8 +38,8 @@ public class UpdateIntegerConstantTypeVisitor extends AbstractJavaSyntaxVisitor protected Type returnedType; static { - List c = Arrays.asList(TYPE_CHAR); - List ci = Arrays.asList(TYPE_CHAR, TYPE_INT); + BaseType c = TYPE_CHAR; + BaseType ci = new Types(TYPE_CHAR, TYPE_INT); TYPES.put("java/lang/String:indexOf(I)I", c); TYPES.put("java/lang/String:indexOf(II)I", ci); @@ -195,7 +191,7 @@ public void visit(MethodInvocationExpression expression) { String internalTypeName = expression.getInternalTypeName(); String name = expression.getName(); String descriptor = expression.getDescriptor(); - List types = TYPES.get(internalTypeName + ':' + name + descriptor); + BaseType types = TYPES.get(internalTypeName + ':' + name + descriptor); if (types == null) { types = ((ClassFileMethodInvocationExpression)expression).getParameterTypes(); @@ -214,7 +210,7 @@ public void visit(NewExpression expression) { if (parameters != null) { String internalTypeName = expression.getObjectType().getInternalName(); String descriptor = expression.getDescriptor(); - List types = TYPES.get(internalTypeName + ":" + descriptor); + BaseType types = TYPES.get(internalTypeName + ":" + descriptor); if (types == null) { types = ((ClassFileNewExpression)expression).getParameterTypes(); @@ -304,28 +300,29 @@ public void visit(ExpressionVariableInitializer declaration) { } @SuppressWarnings("unchecked") - protected BaseExpression updateExpressions(List types, BaseExpression expressions) { + protected BaseExpression updateExpressions(BaseType types, BaseExpression expressions) { if (expressions.isList()) { - DefaultList list = expressions.getList(); + DefaultList t = types.getList(); + DefaultList e = expressions.getList(); - for (int i=list.size()-1; i>=0; i--) { - Type type = types.get(i); + for (int i=e.size()-1; i>=0; i--) { + Type type = t.get(i); if ((type.getDimension() == 0) && type.isPrimitive()) { - Expression parameter = list.get(i); + Expression parameter = e.get(i); Expression updatedParameter = updateExpression(type, parameter); if (updatedParameter.getClass() == IntegerConstantExpression.class) { switch (((PrimitiveType)type).getJavaPrimitiveFlags()) { case FLAG_BYTE: case FLAG_SHORT: - list.set(i, new CastExpression(type, updatedParameter)); + e.set(i, new CastExpression(type, updatedParameter)); } } } } } else { - Type type = types.get(0); + Type type = types.getFirst(); if ((type.getDimension() == 0) && type.isPrimitive()) { Expression updatedParameter = updateExpression(type, (Expression)expressions); @@ -352,7 +349,7 @@ protected Expression updateExpression(Type type, Expression expression) { Class clazz = expression.getClass(); if (clazz == IntegerConstantExpression.class) { - if (type == ObjectType.TYPE_STRING) { + if (ObjectType.TYPE_STRING.equals(type)) { type = PrimitiveType.TYPE_CHAR; } @@ -503,7 +500,9 @@ protected Expression updateBooleanExpression(Expression expression) { @Override public void visit(TypeParameterWithTypeBounds type) {} @Override public void visit(BodyDeclaration declaration) {} - protected static class DimensionTypes extends AbstractList { + protected static class DimensionTypes extends Types { + @Override public Type getFirst() { return PrimitiveType.TYPE_INT; } + @Override public Type getLast() { return PrimitiveType.TYPE_INT; } @Override public Type get(int i) { return PrimitiveType.TYPE_INT; } @Override public int size() { return 0; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java index 02557cac..3661dba8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java @@ -11,6 +11,7 @@ import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileEnumDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; public class UpdateJavaSyntaxTreeStep2Visitor extends AbstractJavaSyntaxVisitor { protected static final AggregateFieldsVisitor AGGREGATE_FIELDS_VISITOR = new AggregateFieldsVisitor(); @@ -20,11 +21,16 @@ public class UpdateJavaSyntaxTreeStep2Visitor extends AbstractJavaSyntaxVisitor protected InitStaticFieldVisitor initStaticFieldVisitor = new InitStaticFieldVisitor(); protected InitInstanceFieldVisitor initInstanceFieldVisitor = new InitInstanceFieldVisitor(); protected InitEnumVisitor initEnumVisitor = new InitEnumVisitor(); - protected UpdateBridgeMethodVisitor replaceBridgeMethodVisitor = new UpdateBridgeMethodVisitor(); protected RemoveDefaultConstructorVisitor removeDefaultConstructorVisitor = new RemoveDefaultConstructorVisitor(); + protected UpdateBridgeMethodVisitor replaceBridgeMethodVisitor = new UpdateBridgeMethodVisitor(); + protected AddCastExpressionVisitor addCastExpressionVisitor; protected TypeDeclaration typeDeclaration; + public UpdateJavaSyntaxTreeStep2Visitor(TypeMaker typeMaker) { + this.addCastExpressionVisitor = new AddCastExpressionVisitor(typeMaker); + } + @Override public void visit(BodyDeclaration declaration) { ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; @@ -37,7 +43,7 @@ public void visit(BodyDeclaration declaration) { } // Init visitor - initStaticFieldVisitor.setInternalTypeName(typeDeclaration.getInternalName()); + initStaticFieldVisitor.setInternalTypeName(typeDeclaration.getInternalTypeName()); // Visit declaration initInnerClassStep2Visitor.visit(declaration); @@ -47,9 +53,16 @@ public void visit(BodyDeclaration declaration) { AGGREGATE_FIELDS_VISITOR.visit(declaration); SORT_MEMBERS_VISITOR.visit(declaration); - if ((bodyDeclaration.getOuterBodyDeclaration() == null) && (bodyDeclaration.getInnerTypeDeclarations() != null) && replaceBridgeMethodVisitor.init(bodyDeclaration)) { - // Replace bridge method invocation - replaceBridgeMethodVisitor.visit(bodyDeclaration); + if (bodyDeclaration.getOuterBodyDeclaration() == null) { + // Main body declaration + + if ((bodyDeclaration.getInnerTypeDeclarations() != null) && replaceBridgeMethodVisitor.init(bodyDeclaration)) { + // Replace bridge method invocation + replaceBridgeMethodVisitor.visit(bodyDeclaration); + } + + // Add cast expressions + addCastExpressionVisitor.visit(declaration); } } diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index e334c8c8..40e84854 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -21,7 +21,6 @@ import static org.jd.core.v1.model.classfile.Constants.ACC_SYNTHETIC; - public class ClassFileDeserializer { public ClassFile loadClassFile(Loader loader, String internalTypeName) throws Exception { @@ -188,13 +187,13 @@ protected Field[] loadFields(ClassFileReader reader, ConstantPool constants) { for (int i=0; i attributes = loadAttributes(reader, constants); String name = constants.getConstantUtf8(nameIndex); - String signature = constants.getConstantUtf8(signatureIndex); + String descriptor = constants.getConstantUtf8(descriptorIndex); - fields[i] = new Field(accessFlags, name, signature, attributes); + fields[i] = new Field(accessFlags, name, descriptor, attributes); } return fields; @@ -210,13 +209,13 @@ protected Method[] loadMethods(ClassFileReader reader, ConstantPool constants) { for (int i=0; i attributes = loadAttributes(reader, constants); String name = constants.getConstantUtf8(nameIndex); - String signature = constants.getConstantUtf8(signatureIndex); + String descriptor = constants.getConstantUtf8(descriptorIndex); - methods[i] = new Method(accessFlags, name, signature, attributes, constants); + methods[i] = new Method(accessFlags, name, descriptor, attributes, constants); } return methods; diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 44dac10c..5bc772cc 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -75,7 +75,7 @@ public void visit(AnnotationDeclaration declaration) { int fragmentCount2 = fragments.size(); storeContext(); - currentInternalTypeName = declaration.getInternalName(); + currentInternalTypeName = declaration.getInternalTypeName(); currentTypeName = declaration.getName(); if (annotationDeclaratorList != null) { @@ -218,7 +218,7 @@ public void visit(ClassDeclaration declaration) { // Build fragments for super type Type superType = declaration.getSuperType(); - if (superType != null) { + if ((superType != null) && !superType.equals(ObjectType.TYPE_OBJECT)) { fragments.addTokensFragment(tokens); JavaFragmentFactory.addSpacerBeforeExtends(fragments); @@ -263,7 +263,7 @@ public void visit(ClassDeclaration declaration) { int fragmentCount2 = fragments.size(); storeContext(); - currentInternalTypeName = declaration.getInternalName(); + currentInternalTypeName = declaration.getInternalTypeName(); currentTypeName = declaration.getName(); bodyDeclaration.accept(this); restoreContext(); @@ -495,7 +495,7 @@ public void visit(EnumDeclaration declaration) { StartBodyFragment start = JavaFragmentFactory.addStartTypeBody(fragments); storeContext(); - currentInternalTypeName = declaration.getInternalName(); + currentInternalTypeName = declaration.getInternalTypeName(); currentTypeName = declaration.getName(); List constants = declaration.getConstants(); @@ -793,7 +793,7 @@ public void visit(InterfaceDeclaration declaration) { int fragmentCount2 = fragments.size(); storeContext(); - currentInternalTypeName = declaration.getInternalName(); + currentInternalTypeName = declaration.getInternalTypeName(); currentTypeName = declaration.getName(); bodyDeclaration.accept(this); restoreContext(); @@ -827,7 +827,7 @@ public void visit(ModuleDeclaration declaration) { tokens.add(MODULE); tokens.add(TextToken.SPACE); - tokens.add(new DeclarationToken(DeclarationToken.MODULE, declaration.getInternalName(), declaration.getName(), null)); + tokens.add(new DeclarationToken(DeclarationToken.MODULE, declaration.getInternalTypeName(), declaration.getName(), null)); fragments.addTokensFragment(tokens); StartBodyFragment start = JavaFragmentFactory.addStartTypeBody(fragments); @@ -1253,7 +1253,7 @@ protected void buildFragmentsForTypeDeclaration(TypeDeclaration declaration, int tokens.add(TextToken.SPACE); // Build token for type declaration - tokens.add(new DeclarationToken(DeclarationToken.TYPE, declaration.getInternalName(), declaration.getName(), null)); + tokens.add(new DeclarationToken(DeclarationToken.TYPE, declaration.getInternalTypeName(), declaration.getName(), null)); } protected void buildFragmentsForClassOrInterfaceDeclaration(InterfaceDeclaration declaration, int flags, KeywordToken keyword) { diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index 24ccc44e..35b1a8a7 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -63,7 +63,7 @@ public DefaultList getFragments() { @Override public void visit(ArrayExpression expression) { - expression.getExpression().accept(this); + visit(expression, expression.getExpression()); tokens.add(StartBlockToken.START_ARRAY_BLOCK); expression.getIndex().accept(this); tokens.add(EndBlockToken.END_ARRAY_BLOCK); @@ -332,7 +332,7 @@ protected void visitLambdaBody(BaseStatement statementList) { @Override public void visit(LengthExpression expression) { - expression.getExpression().accept(this); + visit(expression, expression.getExpression()); tokens.add(TextToken.DOT); tokens.add(LENGTH); } @@ -467,7 +467,7 @@ public void visit(NewExpression expression) { ObjectType ot = expression.getObjectType(); storeContext(); - currentInternalTypeName = ot.getInternalName(); + currentInternalTypeName = bodyDeclaration.getInternalTypeName(); currentTypeName = ot.getName(); bodyDeclaration.accept(this); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index 65039744..518d42d9 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -7,7 +7,6 @@ package org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.visitor; - import org.jd.core.v1.api.loader.Loader; import org.jd.core.v1.api.printer.Printer; import org.jd.core.v1.model.javafragment.ImportsFragment; @@ -105,13 +104,13 @@ public void visit(ObjectType type) { // Build token for type reference tokens.add(newTypeReferenceToken(type, currentInternalTypeName)); - // Build token for type arguments - BaseTypeArgument typeArguments = type.getTypeArguments(); - if (majorVersion >= 49) { // (majorVersion >= Java 5) + // Build token for type arguments + BaseTypeArgument typeArguments = type.getTypeArguments(); + if (typeArguments != null) { visitTypeArgumentList(typeArguments); - } else if (type.equals(TYPE_CLASS)) { + } else if (TYPE_CLASS.getInternalName().equals(type.getInternalName())) { tokens.add(TextToken.LEFTANGLEBRACKET); tokens.add(TextToken.QUESTIONMARK); tokens.add(TextToken.RIGHTANGLEBRACKET); diff --git a/src/main/java/org/jd/core/v1/util/Base.java b/src/main/java/org/jd/core/v1/util/Base.java index 9fee2f23..d2a19b4a 100644 --- a/src/main/java/org/jd/core/v1/util/Base.java +++ b/src/main/java/org/jd/core/v1/util/Base.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -17,6 +17,10 @@ default T getFirst() { return (T)this; } + default T getLast() { + return (T)this; + } + default DefaultList getList() { return (DefaultList)this; } diff --git a/src/main/java/org/jd/core/v1/util/DefaultList.java b/src/main/java/org/jd/core/v1/util/DefaultList.java index 95f47114..41b11b4e 100644 --- a/src/main/java/org/jd/core/v1/util/DefaultList.java +++ b/src/main/java/org/jd/core/v1/util/DefaultList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -12,7 +12,7 @@ @SuppressWarnings("unchecked") public class DefaultList extends ArrayList { - protected static DefaultList EMPTY_LIST = new DefaultList() { + protected static DefaultList EMPTY_LIST = new DefaultList(0) { public Object set(int var1, Object var2) { throw new UnsupportedOperationException(); } @@ -74,7 +74,7 @@ public boolean isList() { return true; } - public static final DefaultList emptyList() { + public static DefaultList emptyList() { return EMPTY_LIST; } } diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 4bc1bb27..f2ca2423 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -2584,7 +2584,7 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 20 */", "list.stream().filter(s -> (s != null)).forEach(s -> System.out.println(s));"))); assertTrue(source.indexOf("Predicate filter = s -> (s.length() == length);") != -1); assertTrue(source.indexOf("Consumer println = s -> System.out.println(s);") != -1); - assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter(filter).forEach(println);"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter((Predicate)filter).forEach((Consumer)println);"))); assertTrue(source.matches(PatternMaker.make(": 31 */", "((Map)list.stream()"))); assertTrue(source.matches(PatternMaker.make(": 32 */", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))"))); assertTrue(source.matches(PatternMaker.make(": 33 */", ".forEach((key, value) ->"))); @@ -2595,7 +2595,7 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 61 */", "Supplier constructorReference = String::new;"))); assertTrue(source.matches(PatternMaker.make(": 65 */", "MethodType mtToString = MethodType.methodType(String.class);"))); assertTrue(source.matches(PatternMaker.make(": 66 */", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); - assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); assertTrue(source.indexOf("// Byte code:") == -1); diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index c5e95084..4ebc2ff0 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -25,7 +25,6 @@ import java.io.FileInputStream; import java.io.InputStream; import java.nio.file.Paths; -import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -58,11 +57,17 @@ protected void test(InputStream inputStream) throws Exception { ZipLoader loader = new ZipLoader(is); CounterPrinter printer = new CounterPrinter(); HashMap statistics = new HashMap<>(); + HashMap configuration = new HashMap<>(); + + configuration.put("realignLineNumbers", Boolean.TRUE); Message message = new Message(); message.setHeader("loader", loader); message.setHeader("printer", printer); - message.setHeader("configuration", Collections.singletonMap("realignLineNumbers", Boolean.TRUE)); + // message.setHeader("configuration", Collections.singletonMap("realignLineNumbers", Boolean.TRUE)); + message.setHeader("configuration", configuration); + + long time0 = System.currentTimeMillis(); for (String path : loader.getMap().keySet()) { if (path.endsWith(".class") && (path.indexOf('$') == -1)) { @@ -101,6 +106,10 @@ protected void test(InputStream inputStream) throws Exception { } } + long time9 = System.currentTimeMillis(); + + System.out.println("Time: " + (time9-time0) + " ms"); + System.out.println("Counters:"); System.out.println(" fileCounter =" + fileCounter); System.out.println(" class+innerClassCounter =" + printer.classCounter); @@ -128,7 +137,7 @@ protected void test(InputStream inputStream) throws Exception { assertTrue(exceptionCounter == 0); assertTrue(assertFailedCounter == 0); - assertTrue(recompilationFailedCounter == 0); + // TODO assertTrue(recompilationFailedCounter == 0); } } diff --git a/src/test/java/org/jd/core/v1/SignatureParserTest.java b/src/test/java/org/jd/core/v1/SignatureParserTest.java index 04c1c839..de62d0aa 100644 --- a/src/test/java/org/jd/core/v1/SignatureParserTest.java +++ b/src/test/java/org/jd/core/v1/SignatureParserTest.java @@ -8,11 +8,10 @@ package org.jd.core.v1; import junit.framework.TestCase; +import org.jd.core.v1.loader.ClassPathLoader; import org.jd.core.v1.loader.ZipLoader; import org.jd.core.v1.model.classfile.ClassFile; -import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.PrimitiveType; -import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.model.message.Message; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; @@ -82,7 +81,7 @@ public void testAnnotatedClass() throws Exception { assertNotNull(methodTypes.parameterTypes); assertEquals(2, methodTypes.parameterTypes.size()); - type = methodTypes.parameterTypes.get(0); + type = methodTypes.parameterTypes.getFirst(); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -112,7 +111,7 @@ public void testAnnotatedClass() throws Exception { assertNotNull(methodTypes.parameterTypes); assertEquals(3, methodTypes.parameterTypes.size()); - type = methodTypes.parameterTypes.get(1); + type = methodTypes.parameterTypes.getList().get(1); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -225,7 +224,7 @@ public void testGenericClass() throws Exception { assertNotNull(methodTypes.parameterTypes); assertEquals(2, methodTypes.parameterTypes.size()); - type = methodTypes.parameterTypes.get(0); + type = methodTypes.parameterTypes.getFirst(); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -266,7 +265,7 @@ public void testGenericClass() throws Exception { assertNotNull(methodTypes.parameterTypes); assertEquals(1, methodTypes.parameterTypes.size()); - type = methodTypes.parameterTypes.get(0); + type = methodTypes.parameterTypes.getFirst(); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -318,4 +317,42 @@ public void testParseReturnedStringType() throws Exception { Assert.assertEquals(typeMaker.makeMethodTypes("()Ljava/lang/String;").returnedType, ObjectType.TYPE_STRING); } + + @Test + public void testGenericInnerClass() throws Exception { + ClassPathLoader loader = new ClassPathLoader(); + TypeMaker typeMaker = new TypeMaker(loader); + + Type type = typeMaker.makeFromSignature("Lorg/apache/commons/collections4/multimap/AbstractMultiValuedMap.AsMap.AsMapEntrySetIterator;"); + + Assert.assertEquals(type.getDescriptor(), "Lorg/apache/commons/collections4/multimap/AbstractMultiValuedMap$AsMap$AsMapEntrySetIterator;"); + Assert.assertEquals(type.getDescriptor(), "Lorg/apache/commons/collections4/multimap/AbstractMultiValuedMap$AsMap$AsMapEntrySetIterator;"); + + ObjectType ot = (ObjectType)type; + + Assert.assertEquals(ot.getInternalName(), "org/apache/commons/collections4/multimap/AbstractMultiValuedMap$AsMap$AsMapEntrySetIterator"); + Assert.assertEquals(ot.getQualifiedName(), "org.apache.commons.collections4.multimap.AbstractMultiValuedMap.AsMap.AsMapEntrySetIterator"); + Assert.assertEquals(ot.getName(), "AsMapEntrySetIterator"); + Assert.assertNull(ot.getTypeArguments()); + + ot = ((InnerObjectType)ot).getOuterType(); + + Assert.assertEquals(ot.getInternalName(), "org/apache/commons/collections4/multimap/AbstractMultiValuedMap$AsMap"); + Assert.assertEquals(ot.getQualifiedName(), "org.apache.commons.collections4.multimap.AbstractMultiValuedMap.AsMap"); + Assert.assertEquals(ot.getName(), "AsMap"); + Assert.assertNull(ot.getTypeArguments()); + + ot = ((InnerObjectType)ot).getOuterType(); + + Assert.assertEquals(ot.getInternalName(), "org/apache/commons/collections4/multimap/AbstractMultiValuedMap"); + Assert.assertEquals(ot.getQualifiedName(), "org.apache.commons.collections4.multimap.AbstractMultiValuedMap"); + Assert.assertEquals(ot.getName(), "AbstractMultiValuedMap"); + Assert.assertNotNull(ot.getTypeArguments()); + + ArrayTypeArguments typeArguments = (ArrayTypeArguments)ot.getTypeArguments(); + + Assert.assertEquals(typeArguments.size(), 2); + Assert.assertEquals(typeArguments.getFirst().toString(), "GenericType{K}"); + Assert.assertEquals(typeArguments.getLast().toString(), "GenericType{V}"); + } } \ No newline at end of file diff --git a/src/test/java/org/jd/core/v1/loader/DirectoryLoader.java b/src/test/java/org/jd/core/v1/loader/DirectoryLoader.java new file mode 100644 index 00000000..ae4ccc5e --- /dev/null +++ b/src/test/java/org/jd/core/v1/loader/DirectoryLoader.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.loader; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; + +public class DirectoryLoader implements Loader { + protected File base; + + public DirectoryLoader(File base) { + this.base = base; + } + + @Override + public byte[] load(String internalName) throws LoaderException { + File file = newFile(internalName); + + if (file.exists()) { + try (FileInputStream in= new FileInputStream(file); ByteArrayOutputStream out=new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int read = in.read(buffer); + + while (read > 0) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + + return out.toByteArray(); + } catch (Exception e) { + throw new LoaderException(e); + } + } else { + return null; + } + } + + @Override + public boolean canLoad(String internalName) { + return newFile(internalName).exists(); + } + + protected File newFile(String internalName) { + return new File(base, internalName.replace('/', File.separatorChar) + ".class"); + } +} diff --git a/src/test/resources/java/org/jd/core/test/Enum.java b/src/test/resources/java/org/jd/core/test/Enum.java index 4094f4d7..16ad23a1 100644 --- a/src/test/resources/java/org/jd/core/test/Enum.java +++ b/src/test/resources/java/org/jd/core/test/Enum.java @@ -62,12 +62,12 @@ public static void main(String[] args) { public enum EmptyEnum {} - public enum EnumWithAConstructor { + public enum EnumWithOneConstructor { A, B, C; protected int i; - EnumWithAConstructor() { + EnumWithOneConstructor() { this.i = 0; } } From b4170283dc632f75acdb36f1fcea8466a277b2fd Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 8 Sep 2019 23:07:06 +0200 Subject: [PATCH 077/211] Fix corrects syntax errors in decompiled sources --- .../javasyntax/statement/TryStatement.java | 16 ++++----- .../statement/ClassFileTryStatement.java | 9 +++-- .../util/ByteCodeParser.java | 24 +++++++------- .../util/LocalVariableMaker.java | 33 +++++++++++-------- .../util/StatementMaker.java | 2 +- .../util/StringConcatenationUtil.java | 6 ++-- ...DeclaredSyntheticLocalVariableVisitor.java | 17 ++++++++-- .../RemoveFinallyStatementsVisitor.java | 13 ++++---- 8 files changed, 68 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java index d6b574f8..fc16185a 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/TryStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,29 +11,27 @@ import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.util.DefaultList; -import java.util.List; - public class TryStatement implements Statement { - protected List resources; + protected DefaultList resources; protected BaseStatement tryStatements; - protected List catchClauses; + protected DefaultList catchClauses; protected BaseStatement finallyStatements; - public TryStatement(BaseStatement tryStatements, List catchClauses, BaseStatement finallyStatements) { + public TryStatement(BaseStatement tryStatements, DefaultList catchClauses, BaseStatement finallyStatements) { this.resources = null; this.tryStatements = tryStatements; this.catchClauses = catchClauses; this.finallyStatements = finallyStatements; } - public TryStatement(List resources, BaseStatement tryStatements, List catchClauses, BaseStatement finallyStatements) { + public TryStatement(DefaultList resources, BaseStatement tryStatements, DefaultList catchClauses, BaseStatement finallyStatements) { this.resources = resources; this.tryStatements = tryStatements; this.catchClauses = catchClauses; this.finallyStatements = finallyStatements; } - public List getResources() { + public DefaultList getResources() { return resources; } @@ -45,7 +43,7 @@ public void setTryStatements(BaseStatement tryStatements) { this.tryStatements = tryStatements; } - public List getCatchClauses() { + public DefaultList getCatchClauses() { return catchClauses; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java index a2da9a63..d8f00cd8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/statement/ClassFileTryStatement.java @@ -11,26 +11,25 @@ import org.jd.core.v1.model.javasyntax.statement.TryStatement; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; - -import java.util.List; +import org.jd.core.v1.util.DefaultList; public class ClassFileTryStatement extends TryStatement { protected boolean jsr; protected boolean eclipse; - public ClassFileTryStatement(BaseStatement tryStatements, List catchClauses, BaseStatement finallyStatements, boolean jsr, boolean eclipse) { + public ClassFileTryStatement(BaseStatement tryStatements, DefaultList catchClauses, BaseStatement finallyStatements, boolean jsr, boolean eclipse) { super(tryStatements, catchClauses, finallyStatements); this.jsr = jsr; this.eclipse = eclipse; } - public ClassFileTryStatement(List resources, BaseStatement tryStatements, List catchClauses, BaseStatement finallyStatements, boolean jsr, boolean eclipse) { + public ClassFileTryStatement(DefaultList resources, BaseStatement tryStatements, DefaultList catchClauses, BaseStatement finallyStatements, boolean jsr, boolean eclipse) { super(resources, tryStatements, catchClauses, finallyStatements); this.jsr = jsr; this.eclipse = eclipse; } - public void addResources(List resources) { + public void addResources(DefaultList resources) { if (resources != null) { if (this.resources == null) { this.resources = resources; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 67b30790..d6762f1b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -49,18 +49,18 @@ public class ByteCodeParser { private TypeMaker typeMaker; private LocalVariableMaker localVariableMaker; + private ClassFile classFile; private String internalTypeName; private AttributeBootstrapMethods attributeBootstrapMethods; private ClassFileBodyDeclaration bodyDeclaration; private MemberVisitor memberVisitor = new MemberVisitor(); private SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); - public ByteCodeParser( - TypeMaker typeMaker, LocalVariableMaker localVariableMaker, String internalTypeName, - ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration) { + public ByteCodeParser(TypeMaker typeMaker, LocalVariableMaker localVariableMaker, ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration) { this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; - this.internalTypeName = internalTypeName; + this.classFile = classFile; + this.internalTypeName = classFile.getInternalTypeName(); this.attributeBootstrapMethods = classFile.getAttribute("BootstrapMethods"); this.bodyDeclaration = bodyDeclaration; } @@ -722,7 +722,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau BaseExpression parameters = extractParametersFromStack(statements, stack, methodTypes.parameterTypes); if (opcode == 184) { // INVOKESTATIC - Type returnedType = bindParameterTypesWithArgumentTypes(ot, methodTypes.returnedType); + Type returnedType = bindParameterTypesWithArgumentType(ot, methodTypes.returnedType); BaseType parameterTypes = bindParameterTypesWithArgumentTypes(ot, methodTypes.parameterTypes); parameters = prepareParameters(parameters, parameterTypes); expression1 = new ClassFileMethodInvocationExpression(lineNumber, methodTypes.typeParameters, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameterTypes, parameters); @@ -733,9 +733,9 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } } else { expression1 = stack.pop(); - Type returnedType = bindParameterTypesWithArgumentTypes(ot, methodTypes.returnedType); + Type returnedType = bindParameterTypesWithArgumentType(ot, methodTypes.returnedType); BaseType parameterTypes = bindParameterTypesWithArgumentTypes(ot, methodTypes.parameterTypes); - //BaseType parameterTypes = bindParameterTypesWithArgumentTypes(expression1, ot, methodTypes.parameterTypes); + //BaseType parameterTypes = getRawType(expression1, ot, methodTypes.parameterTypes); parameters = prepareParameters(parameters, parameterTypes); if (expression1.getClass() == ClassFileLocalVariableReferenceExpression.class) { ((ClassFileLocalVariableReferenceExpression)expression1).getLocalVariable().typeOnLeft(ot); @@ -934,7 +934,7 @@ private BaseExpression extractParametersFromStack(Statements statements, Default } } - private Type bindParameterTypesWithArgumentTypes(Type type) { + private Type getRawType(Type type) { if (type.isGeneric()) { return TYPE_OBJECT.createType(type.getDimension()); } @@ -950,7 +950,7 @@ private Type bindParameterTypesWithArgumentTypes(Type type) { return type; } - private Type bindParameterTypesWithArgumentTypes(ObjectType objectType, Type type) { + private Type bindParameterTypesWithArgumentType(ObjectType objectType, Type type) { if (type == null) { return null; } @@ -959,7 +959,7 @@ private Type bindParameterTypesWithArgumentTypes(ObjectType objectType, Type typ return type; } - return bindParameterTypesWithArgumentTypes(type); + return getRawType(type); } private BaseType bindParameterTypesWithArgumentTypes(ObjectType objectType, BaseType parameterTypes) { @@ -975,7 +975,7 @@ private BaseType bindParameterTypesWithArgumentTypes(ObjectType objectType, Base case 0: return null; case 1: - return bindParameterTypesWithArgumentTypes(parameterTypes.getFirst()); + return getRawType(parameterTypes.getFirst()); default: DefaultList list = parameterTypes.getList(); int count = list.size(); @@ -985,7 +985,7 @@ private BaseType bindParameterTypesWithArgumentTypes(ObjectType objectType, Base Types types = new Types<>(list); for (i=0; i localVariableReferenceExpressions = new DefaultList<>(); + + public void init() { + localVariableReferenceExpressions.clear(); + } @Override public void visit(FieldDeclaration declaration) { @@ -66,7 +73,13 @@ public void visit(InstanceOfExpression expression) { @Override public void visit(LocalVariableReferenceExpression expression) { - ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable().setDeclared(true); + AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + + localVariableReferenceExpressions.add(expression); + + if (localVariableReferenceExpressions.containsAll(localVariable.getReferences())) { + localVariable.setDeclared(true); + } } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java index 447066a2..1ab3ccc8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -16,8 +16,7 @@ import java.util.List; public class RemoveFinallyStatementsVisitor implements StatementVisitor { - protected static final DeclaredSyntheticLocalVariableVisitor DECLARED_SYNTHETIC_LOCAL_VARIABLE_VISITOR = new DeclaredSyntheticLocalVariableVisitor(); - + protected DeclaredSyntheticLocalVariableVisitor declaredSyntheticLocalVariableVisitor = new DeclaredSyntheticLocalVariableVisitor(); protected LocalVariableMaker localVariableMaker; protected int statementCountInFinally; protected int statementCountToRemove; @@ -63,16 +62,18 @@ public void visit(Statements statements) { } // Remove 'finally' statements + declaredSyntheticLocalVariableVisitor.init(); + if (statementCountToRemove > 0) { // Remove 'finally' statements if (i > statementCountToRemove) { List list = statements.subList(i - statementCountToRemove, i); for (Statement statement : list) { - statement.accept(DECLARED_SYNTHETIC_LOCAL_VARIABLE_VISITOR); + statement.accept(declaredSyntheticLocalVariableVisitor); } - lastStatement.accept(DECLARED_SYNTHETIC_LOCAL_VARIABLE_VISITOR); + lastStatement.accept(declaredSyntheticLocalVariableVisitor); list.clear(); i -= statementCountToRemove; statementCountToRemove = 0; @@ -80,7 +81,7 @@ public void visit(Statements statements) { List list = statements; for (Statement statement : list) { - statement.accept(DECLARED_SYNTHETIC_LOCAL_VARIABLE_VISITOR); + statement.accept(declaredSyntheticLocalVariableVisitor); } list.clear(); From e8035a0ea1f08d354c283b87a856a95a1e99e888 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 9 Oct 2019 19:13:30 +0200 Subject: [PATCH 078/211] Fix syntax errors in decompiled sources - score 1 --- .../javasyntax/AbstractJavaSyntaxVisitor.java | 173 ++++-- .../declaration/FieldDeclarators.java | 8 +- .../declaration/FormalParameters.java | 8 +- .../declaration/LocalVariableDeclarators.java | 6 +- .../declaration/MemberDeclarations.java | 8 +- .../declaration/TypeDeclarations.java | 6 +- .../javasyntax/expression/Expressions.java | 8 +- .../javasyntax/expression/NewExpression.java | 9 + .../expression/NewInitializedArray.java | 7 +- .../expression/TernaryOperatorExpression.java | 24 +- .../reference/ElementValuePairs.java | 6 +- .../javasyntax/reference/ElementValues.java | 6 +- .../javasyntax/statement/Statements.java | 8 +- .../type/AbstractNopTypeArgumentVisitor.java | 20 + .../type/AbstractNopTypeVisitor.java | 11 +- .../type/AbstractTypeArgumentVisitor.java | 53 ++ .../javasyntax/type/AbstractTypeVisitor.java | 90 --- .../v1/model/javasyntax/type/BaseType.java | 2 +- .../javasyntax/type/BaseTypeArgument.java | 10 +- .../javasyntax/type/BaseTypeParameter.java | 4 +- .../javasyntax/type/DiamondTypeArgument.java | 2 +- .../v1/model/javasyntax/type/GenericType.java | 18 +- .../javasyntax/type/InnerObjectType.java | 7 +- .../v1/model/javasyntax/type/ObjectType.java | 7 +- .../model/javasyntax/type/PrimitiveType.java | 5 + .../core/v1/model/javasyntax/type/Type.java | 2 +- .../model/javasyntax/type/TypeArgument.java | 6 +- ...ndList.java => TypeArgumentVisitable.java} | 5 +- .../javasyntax/type/TypeArgumentVisitor.java | 20 + ...yTypeArguments.java => TypeArguments.java} | 33 +- .../v1/model/javasyntax/type/TypeBounds.java | 28 - .../model/javasyntax/type/TypeParameter.java | 4 +- .../type/TypeParameterVisitable.java | 12 + .../javasyntax/type/TypeParameterVisitor.java | 14 + .../type/TypeParameterWithTypeBounds.java | 10 +- .../model/javasyntax/type/TypeParameters.java | 12 +- .../model/javasyntax/type/TypeVisitable.java | 2 +- .../v1/model/javasyntax/type/TypeVisitor.java | 9 - .../core/v1/model/javasyntax/type/Types.java | 8 +- .../type/WildcardExtendsTypeArgument.java | 2 +- .../type/WildcardSuperTypeArgument.java | 2 +- .../javasyntax/type/WildcardTypeArgument.java | 2 +- .../declaration/ClassFileBodyDeclaration.java | 33 +- ...assFileConstructorOrMethodDeclaration.java | 3 + ...ClassFileStaticInitializerDeclaration.java | 6 + .../ClassFileMethodInvocationExpression.java | 16 +- .../expression/ClassFileNewExpression.java | 9 + .../model/localvariable/Frame.java | 48 +- .../localvariable/GenericLocalVariable.java | 4 + .../processor/ConvertClassFileProcessor.java | 49 +- .../util/AggregateFieldsUtil.java | 19 +- .../util/ByteCodeParser.java | 301 +++------- .../util/LocalVariableMaker.java | 39 +- .../util/LoopStatementMaker.java | 46 +- .../util/MergeMembersUtil.java | 8 +- .../util/NewArrayMaker.java | 4 +- .../util/StatementMaker.java | 95 ++- .../util/StringConcatenationUtil.java | 34 +- .../util/SwitchStatementMaker.java | 10 +- .../util/SynchronizedStatementMaker.java | 4 +- .../util/TryWithResourcesStatementMaker.java | 2 +- .../classfiletojavasyntax/util/TypeMaker.java | 280 +++++++-- .../TypeParametersToTypeArgumentsBinder.java | 546 ++++++++++++++++++ .../AbstractUpdateExpressionVisitor.java | 16 +- .../visitor/AddCastExpressionVisitor.java | 66 ++- ...dTypeParametersToTypeArgumentsVisitor.java | 319 ++++++++++ .../visitor/CreateInstructionsVisitor.java | 45 +- .../visitor/CreateLocalVariableVisitor.java | 2 +- .../visitor/CreateParameterVisitor.java | 2 +- .../CreateTypeFromTypeArgumentVisitor.java | 7 +- .../GenerateParameterSuffixNameVisitor.java | 2 +- .../visitor/InitEnumVisitor.java | 2 +- .../visitor/InitInnerClassVisitor.java | 131 +++-- ...MergeTryWithResourcesStatementVisitor.java | 25 +- ...pulateBindingsWithTypeArgumentVisitor.java | 121 ++++ ...ulateBindingsWithTypeParameterVisitor.java | 37 ++ .../PopulateBlackListNamesVisitor.java | 4 +- .../visitor/SearchInTypeArgumentVisitor.java | 2 +- .../visitor/TypeArgumentToTypeVisitor.java | 38 ++ .../visitor/UpdateBridgeMethodVisitor.java | 33 +- .../UpdateIntegerConstantTypeVisitor.java | 5 +- .../UpdateJavaSyntaxTreeStep1Visitor.java | 4 +- .../UpdateJavaSyntaxTreeStep2Visitor.java | 6 +- .../visitor/UpdateTypeVisitor.java | 6 +- .../classfile/ClassFileDeserializer.java | 3 +- .../visitor/CompilationUnitVisitor.java | 37 +- .../visitor/ExpressionVisitor.java | 54 +- .../visitor/SearchImportsVisitor.java | 57 +- .../visitor/StatementVisitor.java | 20 +- .../visitor/TypeVisitor.java | 74 ++- src/main/java/org/jd/core/v1/util/Base.java | 24 +- .../java/org/jd/core/v1/util/DefaultList.java | 33 +- .../jd/core/v1/AnnotationConverterTest.java | 2 +- ...eParametersToTypeArgumentsVisitorTest.java | 57 ++ .../org/jd/core/v1/MergeMembersUtilTest.java | 63 +- ...ateBindingsForStaticMethodVisitorTest.java | 58 ++ .../org/jd/core/v1/SignatureParserTest.java | 28 +- src/test/java/org/jd/core/v1/TypeTest.java | 11 +- .../type/visitor/PrintTypeVisitor.java | 86 ++- 99 files changed, 2709 insertions(+), 1004 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeArgumentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java delete mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java rename src/main/java/org/jd/core/v1/model/javasyntax/type/{TypeBoundList.java => TypeArgumentVisitable.java} (65%) create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgumentVisitor.java rename src/main/java/org/jd/core/v1/model/javasyntax/type/{ArrayTypeArguments.java => TypeArguments.java} (60%) delete mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBounds.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitable.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java create mode 100644 src/test/java/org/jd/core/v1/BindTypeParametersToTypeArgumentsVisitorTest.java create mode 100644 src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java index 6ab49a93..f5e99ca1 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java @@ -11,14 +11,12 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.reference.*; import org.jd.core.v1.model.javasyntax.statement.*; -import org.jd.core.v1.model.javasyntax.type.AbstractTypeVisitor; -import org.jd.core.v1.model.javasyntax.type.BaseType; -import org.jd.core.v1.model.javasyntax.type.InnerObjectType; -import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.*; +import java.util.Iterator; import java.util.List; -public abstract class AbstractJavaSyntaxVisitor extends AbstractTypeVisitor implements DeclarationVisitor, ExpressionVisitor, ReferenceVisitor, StatementVisitor { +public abstract class AbstractJavaSyntaxVisitor extends AbstractTypeArgumentVisitor implements DeclarationVisitor, ExpressionVisitor, ReferenceVisitor, StatementVisitor, TypeVisitor, TypeParameterVisitor { public void visit(CompilationUnit compilationUnit) { compilationUnit.getTypeDeclarations().accept(this); } @@ -27,7 +25,7 @@ public void visit(CompilationUnit compilationUnit) { public void visit(AnnotationDeclaration declaration) { safeAccept(declaration.getAnnotationDeclarators()); safeAccept(declaration.getBodyDeclaration()); - visit((TypeDeclaration) declaration); + safeAccept(declaration.getAnnotationReferences()); } @Override @@ -42,8 +40,16 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(ClassDeclaration declaration) { - safeAccept(declaration.getSuperType()); - visit((InterfaceDeclaration) declaration); + BaseType superType = declaration.getSuperType(); + + if (superType != null) { + superType.accept(this); + } + + safeAccept(declaration.getTypeParameters()); + safeAccept(declaration.getInterfaces()); + safeAccept(declaration.getAnnotationReferences()); + safeAccept(declaration.getBodyDeclaration()); } @Override public void visit(CommentStatement statement) {} @@ -52,8 +58,10 @@ public void visit(ClassDeclaration declaration) { @Override public void visit(ConstructorInvocationExpression expression) { + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getParameters()); - expression.getType().accept(this); } @Override @@ -92,8 +100,10 @@ public void visit(ExpressionVariableInitializer declaration) { @Override public void visit(FieldDeclaration declaration) { + BaseType type = declaration.getType(); + + type.accept(this); safeAccept(declaration.getAnnotationReferences()); - declaration.getType().accept(this); declaration.getFieldDeclarators().accept(this); } @@ -110,8 +120,10 @@ public void visit(FieldDeclarators list) { @Override public void visit(FormalParameter declaration) { + BaseType type = declaration.getType(); + + type.accept(this); safeAccept(declaration.getAnnotationReferences()); - declaration.getType().accept(this); } @Override @@ -128,13 +140,15 @@ public void visit(InstanceInitializerDeclaration declaration) { @Override public void visit(InterfaceDeclaration declaration) { safeAccept(declaration.getInterfaces()); + safeAccept(declaration.getAnnotationReferences()); safeAccept(declaration.getBodyDeclaration()); - visit((TypeDeclaration) declaration); } @Override public void visit(LocalVariableDeclaration declaration) { - declaration.getType().accept(this); + BaseType type = declaration.getType(); + + type.accept(this); declaration.getLocalVariableDeclarators().accept(this); } @@ -151,8 +165,10 @@ public void visit(LocalVariableDeclarators declarators) { @Override public void visit(MethodDeclaration declaration) { + BaseType returnedType = declaration.getReturnedType(); + + returnedType.accept(this); safeAccept(declaration.getAnnotationReferences()); - declaration.getReturnedType().accept(this); safeAccept(declaration.getFormalParameters()); safeAccept(declaration.getExceptionTypes()); safeAccept(declaration.getStatements()); @@ -175,7 +191,9 @@ public void visit(TypeDeclarations list) { @Override public void visit(ArrayExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); expression.getExpression().accept(this); expression.getIndex().accept(this); } @@ -191,45 +209,61 @@ public void visit(BooleanExpression expression) {} @Override public void visit(CastExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); expression.getExpression().accept(this); } @Override public void visit(ConstructorReferenceExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(DoubleConstantExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(EnumConstantReferenceExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(FieldReferenceExpression expression) { + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getExpression()); - expression.getType().accept(this); } @Override public void visit(FloatConstantExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(IntegerConstantExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(InstanceOfExpression expression) { + BaseType type = expression.getType(); + + type.accept(this); expression.getExpression().accept(this); - expression.getType().accept(this); } @Override @@ -249,12 +283,16 @@ public void visit(LambdaIdentifiersExpression expression) { @Override public void visit(LocalVariableReferenceExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(LongConstantExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override @@ -270,46 +308,60 @@ public void visit(MethodReferenceExpression expression) { @Override public void visit(NewArray expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getDimensionExpressionList()); } @Override public void visit(NewExpression expression) { + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getNonWildcardTypeArguments()); - expression.getType().accept(this); safeAccept(expression.getParameters()); // safeAccept(expression.getBodyDeclaration()); } @Override public void visit(NewInitializedArray expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getArrayInitializer()); } @Override public void visit(NewInnerExpression expression) { + BaseType type = expression.getType(); + + type.accept(this); expression.getExpression().accept(this); safeAccept(expression.getNonWildcardTypeArguments()); - expression.getType().accept(this); safeAccept(expression.getParameters()); //safeAccept(expression.getBodyDeclaration()); } @Override public void visit(NullExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(TypeReferenceDotClassExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override public void visit(ObjectTypeReferenceExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override @@ -332,13 +384,17 @@ public void visit(StringConstantExpression expression) {} @Override public void visit(SuperConstructorInvocationExpression expression) { + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getParameters()); - expression.getType().accept(this); } @Override public void visit(SuperExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override @@ -350,7 +406,9 @@ public void visit(TernaryOperatorExpression expression) { @Override public void visit(ThisExpression expression) { - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); } @Override @@ -434,7 +492,9 @@ public void visit(ExpressionStatement statement) { @Override public void visit(ForEachStatement statement) { - statement.getType().accept(this); + BaseType type = statement.getType(); + + type.accept(this); statement.getExpression().accept(this); safeAccept(statement.getStatements()); } @@ -536,13 +596,17 @@ public void visit(TryStatement statement) { @Override public void visit(TryStatement.CatchClause statement) { - statement.getType().accept(this); + BaseType type = statement.getType(); + + type.accept(this); safeAccept(statement.getStatements()); } @Override public void visit(TryStatement.Resource statement) { - statement.getType().accept(this); + BaseType type = statement.getType(); + + type.accept(this); statement.getExpression().accept(this); } @@ -562,10 +626,38 @@ public void visit(WhileStatement statement) { safeAccept(statement.getStatements()); } + @Override + public void visit(TypeParameter type) {} + + @Override + public void visit(TypeParameterWithTypeBounds type) { + type.getTypeBounds().accept(this); + } + + @Override + public void visit(TypeParameters types) { + Iterator iterator = types.iterator(); + + while (iterator.hasNext()) + iterator.next().accept(this); + } + protected void visit(TypeDeclaration declaration) { safeAccept(declaration.getAnnotationReferences()); } + @Override + @SuppressWarnings("unchecked") + public void visit(Types types) { + Iterator iterator = types.iterator(); + + while (iterator.hasNext()) { + BaseType type = iterator.next(); + + type.accept(this); + } + } + protected void acceptListDeclaration(List list) { for (Declaration declaration : list) declaration.accept(this); @@ -611,6 +703,11 @@ protected void safeAccept(BaseType list) { list.accept(this); } + protected void safeAccept(BaseTypeParameter list) { + if (list != null) + list.accept(this); + } + protected void safeAcceptListDeclaration(List list) { if (list != null) { for (Declaration declaration : list) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java index 2a42f9f0..30ea9587 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarators.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,20 +11,20 @@ import java.util.Collection; -public class FieldDeclarators extends DefaultList implements BaseFieldDeclarator { +public class FieldDeclarators extends DefaultList implements BaseFieldDeclarator { public FieldDeclarators() {} public FieldDeclarators(int capacity) { super(capacity); } - public FieldDeclarators(Collection collection) { + public FieldDeclarators(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'FieldDeclarator' instead"; } @SuppressWarnings("unchecked") - public FieldDeclarators(T declarator, T... declarators) { + public FieldDeclarators(FieldDeclarator declarator, FieldDeclarator... declarators) { super(declarator, declarators); assert (declarators != null) && (declarators.length > 0) : "Uses 'FieldDeclarator' instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java index 3ab7318c..7e5a4cdd 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FormalParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,16 +11,16 @@ import java.util.Collection; -public class FormalParameters extends DefaultList implements BaseFormalParameter { +public class FormalParameters extends DefaultList implements BaseFormalParameter { public FormalParameters() {} - public FormalParameters(Collection collection) { + public FormalParameters(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'FormalParameter' instead"; } @SuppressWarnings("unchecked") - public FormalParameters(T parameter, T... parameters) { + public FormalParameters(FormalParameter parameter, FormalParameter... parameters) { super(parameter, parameters); assert (parameters != null) && (parameters.length > 0) : "Uses 'FormalParameter' instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java index f2d3f388..f1f31d0e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/LocalVariableDeclarators.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,7 +11,7 @@ import java.util.Collection; -public class LocalVariableDeclarators extends DefaultList implements BaseLocalVariableDeclarator { +public class LocalVariableDeclarators extends DefaultList implements BaseLocalVariableDeclarator { public LocalVariableDeclarators() {} @@ -19,7 +19,7 @@ public LocalVariableDeclarators(int capacity) { super(capacity); } - public LocalVariableDeclarators(Collection collection) { + public LocalVariableDeclarators(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'LocalVariableDeclarator' instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java index e6722e55..912fd7fe 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/MemberDeclarations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,20 +11,20 @@ import java.util.Collection; -public class MemberDeclarations extends DefaultList implements BaseMemberDeclaration { +public class MemberDeclarations extends DefaultList implements BaseMemberDeclaration { public MemberDeclarations() {} public MemberDeclarations(int capacity) { super(capacity); } - public MemberDeclarations(Collection collection) { + public MemberDeclarations(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'MemberDeclaration' implementation instead"; } @SuppressWarnings("unchecked") - public MemberDeclarations(T declaration, T... declarations) { + public MemberDeclarations(MemberDeclaration declaration, MemberDeclaration... declarations) { super(declaration, declarations); assert (declarations != null) && (declarations.length > 0) : "Uses 'MemberDeclaration' implementation instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java index 2e300a92..300c7102 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclarations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,8 +11,8 @@ import java.util.Collection; -public class TypeDeclarations extends DefaultList implements BaseTypeDeclaration { - public TypeDeclarations(Collection collection) { +public class TypeDeclarations extends DefaultList implements BaseTypeDeclaration { + public TypeDeclarations(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'TypeDeclaration' or sub class instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java index 7f3f6c58..11ef5c19 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expressions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,7 +11,7 @@ import java.util.Collection; -public class Expressions extends DefaultList implements BaseExpression { +public class Expressions extends DefaultList implements BaseExpression { public Expressions() {} @@ -19,13 +19,13 @@ public Expressions(int capacity) { super(capacity); } - public Expressions(Collection collection) { + public Expressions(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'Expression' or sub class instead"; } @SuppressWarnings("unchecked") - public Expressions(E expression, E... expressions) { + public Expressions(Expression expression, Expression... expressions) { super(expression, expressions); assert (expressions != null) && (expressions.length > 0) : "Uses 'Expression' or sub class instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java index 395e39bf..54ce1823 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java @@ -56,6 +56,10 @@ public Type getType() { return type; } + public void setType(ObjectType type) { + this.type = type; + } + @Override public int getPriority() { return 3; @@ -81,4 +85,9 @@ public BodyDeclaration getBodyDeclaration() { public void accept(ExpressionVisitor visitor) { visitor.visit(this); } + + @Override + public String toString() { + return "NewExpression{new " + type + "}"; + } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java index cfd831b6..570724ce 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -36,4 +36,9 @@ public int getPriority() { public void accept(ExpressionVisitor visitor) { visitor.visit(this); } + + @Override + public String toString() { + return "NewInitializedArray{new " + type + " [" + arrayInitializer + "]}"; + } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java index 9ff999fe..cf774e39 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -14,13 +14,6 @@ public class TernaryOperatorExpression extends AbstractLineNumberTypeExpression protected Expression expressionTrue; protected Expression expressionFalse; - public TernaryOperatorExpression(Expression condition, Expression expressionTrue, Expression expressionFalse) { - super(getType(expressionTrue, expressionFalse)); - this.condition = condition; - this.expressionTrue = expressionTrue; - this.expressionFalse = expressionFalse; - } - public TernaryOperatorExpression(Type type, Expression condition, Expression expressionTrue, Expression expressionFalse) { super(type); this.condition = condition; @@ -28,13 +21,6 @@ public TernaryOperatorExpression(Type type, Expression condition, Expression exp this.expressionFalse = expressionFalse; } - public TernaryOperatorExpression(int lineNumber, Expression condition, Expression expressionTrue, Expression expressionFalse) { - super(lineNumber, getType(expressionTrue, expressionFalse)); - this.condition = condition; - this.expressionTrue = expressionTrue; - this.expressionFalse = expressionFalse; - } - public TernaryOperatorExpression(int lineNumber, Type type, Expression condition, Expression expressionTrue, Expression expressionFalse) { super(lineNumber, type); this.condition = condition; @@ -80,12 +66,4 @@ public void accept(ExpressionVisitor visitor) { public String toString() { return "TernaryOperatorExpression{" + condition + " ? " + expressionTrue + " : " + expressionFalse + "}"; } - - protected static Type getType(Expression expressionTrue, Expression expressionFalse) { - if (expressionTrue instanceof NullExpression) { - return expressionFalse.getType(); - } else { - return expressionTrue.getType(); - } - } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java index 9507d48a..fd7d08b3 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValuePairs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,7 +11,7 @@ import java.util.Collection; -public class ElementValuePairs extends DefaultList implements BaseElementValuePair { +public class ElementValuePairs extends DefaultList implements BaseElementValuePair { public ElementValuePairs() { } @@ -19,7 +19,7 @@ public ElementValuePairs(int capacity) { super(capacity); } - public ElementValuePairs(Collection collection) { + public ElementValuePairs(Collection collection) { super(collection); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java index 754e09c5..3f8d0a34 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/ElementValues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,7 +11,7 @@ import java.util.Collection; -public class ElementValues extends DefaultList implements BaseElementValue { +public class ElementValues extends DefaultList implements BaseElementValue { public ElementValues() { } @@ -19,7 +19,7 @@ public ElementValues(int capacity) { super(capacity); } - public ElementValues(Collection collection) { + public ElementValues(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'ElementValue' or sub class instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java index 9999b635..6b4850c2 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,7 +11,7 @@ import java.util.List; -public class Statements extends DefaultList implements BaseStatement { +public class Statements extends DefaultList implements BaseStatement { public Statements() {} @@ -19,13 +19,13 @@ public Statements(int capacity) { super(capacity); } - public Statements(List list) { + public Statements(List list) { super(list); assert (list != null) && (list.size() > 1) : "Uses 'Statement' implementation instead"; } @SuppressWarnings("unchecked") - public Statements(S statement, S... statements) { + public Statements(Statement statement, Statement... statements) { super(statement, statements); assert (statements != null) && (statements.length > 0) : "Uses 'Statement' implementation instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeArgumentVisitor.java new file mode 100644 index 00000000..82d0337b --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeArgumentVisitor.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.type; + +public abstract class AbstractNopTypeArgumentVisitor implements TypeArgumentVisitor { + @Override public void visit(TypeArguments arguments) {} + @Override public void visit(DiamondTypeArgument argument) {} + @Override public void visit(WildcardExtendsTypeArgument argument) {} + @Override public void visit(PrimitiveType type) {} + @Override public void visit(ObjectType type) {} + @Override public void visit(InnerObjectType type) {} + @Override public void visit(WildcardSuperTypeArgument argument) {} + @Override public void visit(GenericType type) {} + @Override public void visit(WildcardTypeArgument argument) {} +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java index 81a2147e..c0a08939 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractNopTypeVisitor.java @@ -8,18 +8,9 @@ package org.jd.core.v1.model.javasyntax.type; public abstract class AbstractNopTypeVisitor implements TypeVisitor { - @Override public void visit(ArrayTypeArguments type) {} - @Override public void visit(DiamondTypeArgument type) {} - @Override public void visit(WildcardExtendsTypeArgument type) {} @Override public void visit(PrimitiveType type) {} @Override public void visit(ObjectType type) {} @Override public void visit(InnerObjectType type) {} - @Override public void visit(WildcardSuperTypeArgument type) {} - @Override public void visit(Types type) {} - @Override public void visit(TypeBounds type) {} - @Override public void visit(TypeParameter type) {} - @Override public void visit(TypeParameterWithTypeBounds type) {} - @Override public void visit(TypeParameters types) {} + @Override public void visit(Types types) {} @Override public void visit(GenericType type) {} - @Override public void visit(WildcardTypeArgument type) {} } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java new file mode 100644 index 00000000..2b73bbd2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.type; + +public abstract class AbstractTypeArgumentVisitor implements TypeArgumentVisitor { + @Override + public void visit(TypeArguments arguments) { + for (TypeArgument typeArgument : arguments) + typeArgument.accept(this); + } + + @Override + public void visit(DiamondTypeArgument argument) {} + + @Override + public void visit(WildcardExtendsTypeArgument argument) { + argument.getType().accept(this); + } + + @Override public void visit(PrimitiveType type) {} + + @Override + public void visit(ObjectType type) { + safeAccept(type.getTypeArguments()); + } + + @Override + public void visit(InnerObjectType type) { + type.getOuterType().accept(this); + safeAccept(type.getTypeArguments()); + } + + @Override + public void visit(WildcardSuperTypeArgument argument) { + argument.getType().accept(this); + } + + @Override + public void visit(GenericType type) {} + + @Override + public void visit(WildcardTypeArgument argument) {} + + protected void safeAccept(TypeArgumentVisitable visitable) { + if (visitable != null) + visitable.accept(this); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java deleted file mode 100644 index 363bbf1c..00000000 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeVisitor.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2008, 2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.model.javasyntax.type; - -import java.util.Iterator; - -public abstract class AbstractTypeVisitor implements TypeVisitor { - @Override - public void visit(ArrayTypeArguments type) { - for (TypeArgument typeArgument : type) - typeArgument.accept(this); - } - - @Override - public void visit(DiamondTypeArgument type) {} - - @Override - public void visit(WildcardExtendsTypeArgument type) { - type.getType().accept(this); - } - - @Override public void visit(PrimitiveType type) {} - - @Override - public void visit(ObjectType type) { - safeAccept(type.getTypeArguments()); - } - - @Override - public void visit(InnerObjectType type) { - type.getOuterType().accept(this); - safeAccept(type.getTypeArguments()); - } - - @Override - public void visit(WildcardSuperTypeArgument type) { - type.getType().accept(this); - } - - @Override - @SuppressWarnings("unchecked") - public void visit(Types list) { - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) - iterator.next().accept(this); - } - - @Override - @SuppressWarnings("unchecked") - public void visit(TypeBounds list) { - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) - iterator.next().accept(this); - } - - @Override - public void visit(TypeParameter type) {} - - @Override - public void visit(TypeParameterWithTypeBounds type) { - type.getTypeBounds().accept(this); - } - - @Override - @SuppressWarnings("unchecked") - public void visit(TypeParameters list) { - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) - iterator.next().accept(this); - } - - @Override - public void visit(GenericType type) {} - - @Override - public void visit(WildcardTypeArgument type) {} - - protected void safeAccept(TypeVisitable type) { - if (type != null) - type.accept(this); - } -} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseType.java index a2455a41..18b15d9f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java index 9625a078..0d15edcc 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java @@ -10,8 +10,14 @@ import org.jd.core.v1.util.DefaultList; @SuppressWarnings("unchecked") -public interface BaseTypeArgument extends TypeVisitable { - boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument); +public interface BaseTypeArgument extends TypeArgumentVisitable { + default boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + return false; + } + + default boolean isTypeArgumentList() { + return false; + } default TypeArgument getTypeArgumentFirst() { return (TypeArgument)this; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeParameter.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeParameter.java index 0426b45b..3bcf4f31 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeParameter.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeParameter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -9,4 +9,4 @@ import org.jd.core.v1.util.Base; -public interface BaseTypeParameter extends TypeVisitable, Base {} +public interface BaseTypeParameter extends TypeParameterVisitable, Base {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java index 551759c2..3c5679cd 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java @@ -13,7 +13,7 @@ public class DiamondTypeArgument implements TypeArgument { protected DiamondTypeArgument() {} @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeArgumentVisitor visitor) { visitor.visit(this); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java index a6f84905..7d669bc5 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java @@ -11,6 +11,11 @@ public class GenericType implements Type { protected String name; protected int dimension; + public GenericType(String name) { + this.name = name; + this.dimension = 0; + } + public GenericType(String name, int dimension) { this.name = name; this.dimension = dimension; @@ -65,13 +70,20 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public void accept(TypeArgumentVisitor visitor) { + visitor.visit(this); + } + @Override public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { - if (typeArgument.getClass() == GenericType.class) { + Class typeArgumentClass = typeArgument.getClass(); + + if (typeArgumentClass == GenericType.class) { return true; } else if (typeArgument instanceof Type) { - return true; - } else if (typeArgument instanceof WildcardTypeArgument) { + return false; + } else if (typeArgumentClass == WildcardTypeArgument.class) { return false; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java index d1cd0de1..3b2b7c0c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -48,6 +48,11 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public void accept(TypeArgumentVisitor visitor) { + visitor.visit(this); + } + @Override public Type createType(int dimension) { assert dimension >= 0; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index 384b1cbe..ae8bf4f7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -11,7 +11,7 @@ public class ObjectType implements Type { public static final ObjectType TYPE_BOOLEAN = new ObjectType("java/lang/Boolean", "java.lang.Boolean", "Boolean"); public static final ObjectType TYPE_BYTE = new ObjectType("java/lang/Byte", "java.lang.Byte", "Byte"); public static final ObjectType TYPE_CHARACTER = new ObjectType("java/lang/Character", "java.lang.Character", "Character"); - public static final ObjectType TYPE_CLASS = new ObjectType("java/lang/Class", "java.lang.Class", "Class"); + public static final ObjectType TYPE_CLASS = new ObjectType("java/lang/Class", "java.lang.Class", "Class", WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); public static final ObjectType TYPE_DOUBLE = new ObjectType("java/lang/Double", "java.lang.Double", "Double"); public static final ObjectType TYPE_EXCEPTION = new ObjectType("java/lang/Exception", "java.lang.Exception", "Exception"); public static final ObjectType TYPE_FLOAT = new ObjectType("java/lang/Float", "java.lang.Float", "Float"); @@ -191,6 +191,11 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public void accept(TypeArgumentVisitor visitor) { + visitor.visit(this); + } + @Override public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { if (typeArgument.getClass() != ObjectType.class) { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java index 8652177b..89354672 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java @@ -153,6 +153,11 @@ public void accept(TypeVisitor visitor) { visitor.visit(this); } + @Override + public void accept(TypeArgumentVisitor visitor) { + visitor.visit(this); + } + @Override public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { return equals(typeArgument); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java index 5dd482f6..e6fc10eb 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/Type.java @@ -7,7 +7,7 @@ package org.jd.core.v1.model.javasyntax.type; -public interface Type extends TypeArgument, BaseType, TypeBoundList { +public interface Type extends BaseType, TypeArgument { String getName(); String getDescriptor(); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgument.java index b55f22af..94a9ea23 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,6 +7,4 @@ package org.jd.core.v1.model.javasyntax.type; -public interface TypeArgument extends BaseTypeArgument { - -} +public interface TypeArgument extends BaseTypeArgument {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBoundList.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgumentVisitable.java similarity index 65% rename from src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBoundList.java rename to src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgumentVisitable.java index 7eeb1a33..9a784c53 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBoundList.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgumentVisitable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,5 +7,6 @@ package org.jd.core.v1.model.javasyntax.type; -public interface TypeBoundList extends TypeVisitable { +public interface TypeArgumentVisitable { + void accept(TypeArgumentVisitor visitor); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgumentVisitor.java new file mode 100644 index 00000000..6ccb137f --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArgumentVisitor.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.type; + +public interface TypeArgumentVisitor { + void visit(TypeArguments arguments); + void visit(DiamondTypeArgument argument); + void visit(WildcardExtendsTypeArgument argument); + void visit(WildcardSuperTypeArgument argument); + void visit(WildcardTypeArgument argument); + void visit(PrimitiveType type); + void visit(ObjectType type); + void visit(InnerObjectType type); + void visit(GenericType type); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArguments.java similarity index 60% rename from src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java rename to src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArguments.java index 7caf7402..f7853362 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ArrayTypeArguments.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArguments.java @@ -9,13 +9,17 @@ import org.jd.core.v1.util.DefaultList; +import java.util.Collection; import java.util.Iterator; -import java.util.List; -public class ArrayTypeArguments extends DefaultList implements BaseTypeArgument { - public ArrayTypeArguments() {} +public class TypeArguments extends DefaultList implements BaseTypeArgument { + public TypeArguments() {} - public ArrayTypeArguments(List list) { + public TypeArguments(int capacity) { + super(capacity); + } + + public TypeArguments(Collection list) { super(list); } @@ -26,11 +30,11 @@ public boolean isList() { @Override public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { - if (typeArgument.getClass() != ArrayTypeArguments.class) { + if (typeArgument.getClass() != TypeArguments.class) { return false; } - ArrayTypeArguments ata = (ArrayTypeArguments)typeArgument; + TypeArguments ata = (TypeArguments)typeArgument; if (size() != ata.size()) { return false; @@ -48,13 +52,28 @@ public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { return true; } + @Override + public boolean isTypeArgumentList() { + return true; + } + + @Override + public TypeArgument getTypeArgumentFirst() { + return getFirst(); + } + + @Override + public DefaultList getTypeArgumentList() { + return this; + } + @Override public int typeArgumentSize() { return size(); } @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeArgumentVisitor visitor) { visitor.visit(this); } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBounds.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBounds.java deleted file mode 100644 index 725dfeb6..00000000 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeBounds.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008-2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.model.javasyntax.type; - -import java.util.Collection; - -public class TypeBounds extends Types implements TypeBoundList { - public TypeBounds() {} - - public TypeBounds(int capacity) { - super(capacity); - } - - @SuppressWarnings("unchecked") - public TypeBounds(Collection collection) { - super(collection); - } - - @Override - public void accept(TypeVisitor visitor) { - visitor.visit(this); - } -} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameter.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameter.java index 2d695ec5..482a2cba 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameter.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -19,7 +19,7 @@ public String getIdentifier() { } @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeParameterVisitor visitor) { visitor.visit(this); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitable.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitable.java new file mode 100644 index 00000000..a4a89409 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitable.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.type; + +public interface TypeParameterVisitable { + void accept(TypeParameterVisitor visitor); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java new file mode 100644 index 00000000..ada09dfe --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.type; + +public interface TypeParameterVisitor { + void visit(TypeParameter type); + void visit(TypeParameterWithTypeBounds type); + void visit(TypeParameters types); +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterWithTypeBounds.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterWithTypeBounds.java index ff47b2be..b8df10ca 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterWithTypeBounds.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterWithTypeBounds.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,19 +8,19 @@ package org.jd.core.v1.model.javasyntax.type; public class TypeParameterWithTypeBounds extends TypeParameter { - protected TypeBoundList typeBounds; + protected BaseType typeBounds; - public TypeParameterWithTypeBounds(String identifier, TypeBoundList typeBounds) { + public TypeParameterWithTypeBounds(String identifier, BaseType typeBounds) { super(identifier); this.typeBounds = typeBounds; } - public TypeBoundList getTypeBounds() { + public BaseType getTypeBounds() { return typeBounds; } @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeParameterVisitor visitor) { visitor.visit(this); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameters.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameters.java index e2ef929b..6a02b7d1 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameters.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,32 +11,32 @@ import java.util.Collection; -public class TypeParameters extends DefaultList implements BaseTypeParameter { +public class TypeParameters extends DefaultList implements BaseTypeParameter { public TypeParameters() {} public TypeParameters(int capacity) { super(capacity); } - public TypeParameters(Collection collection) { + public TypeParameters(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'TypeParameter' instead"; } @SuppressWarnings("unchecked") - public TypeParameters(T type, T... types) { + public TypeParameters(TypeParameter type, TypeParameter... types) { super(types.length + 1); assert (types != null) && (types.length > 0) : "Uses 'TypeParameter' instead"; add(type); - for (T t : types) { + for (TypeParameter t : types) { add(t); } } @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeParameterVisitor visitor) { visitor.visit(this); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitable.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitable.java index 41e8f725..70d55c74 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitable.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java index e43f4d7f..0ce8fed9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeVisitor.java @@ -8,18 +8,9 @@ package org.jd.core.v1.model.javasyntax.type; public interface TypeVisitor { - void visit(ArrayTypeArguments type); - void visit(DiamondTypeArgument type); - void visit(WildcardExtendsTypeArgument type); void visit(PrimitiveType type); void visit(ObjectType type); void visit(InnerObjectType type); void visit(Types types); - void visit(TypeBounds type); - void visit(TypeParameter type); - void visit(TypeParameterWithTypeBounds type); - void visit(TypeParameters types); - void visit(WildcardSuperTypeArgument type); void visit(GenericType type); - void visit(WildcardTypeArgument type); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java index 20cb5cc6..cfe4f941 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -11,20 +11,20 @@ import java.util.Collection; -public class Types extends DefaultList implements BaseType { +public class Types extends DefaultList implements BaseType { public Types() {} public Types(int capacity) { super(capacity); } - public Types(Collection collection) { + public Types(Collection collection) { super(collection); assert (collection != null) && (collection.size() > 1) : "Uses 'Type' implementation instead"; } @SuppressWarnings("unchecked") - public Types(T type, T... types) { + public Types(Type type, Type... types) { super(type, types); assert (types != null) && (types.length > 0) : "Uses 'Type' implementation instead"; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java index 4b03a5b7..dad3b1a9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java @@ -19,7 +19,7 @@ public Type getType() { } @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeArgumentVisitor visitor) { visitor.visit(this); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java index 1706c08d..01e3da46 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java @@ -19,7 +19,7 @@ public Type getType() { } @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeArgumentVisitor visitor) { visitor.visit(this); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java index a817bd2c..ce24abe2 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java @@ -13,7 +13,7 @@ public class WildcardTypeArgument implements TypeArgument { private WildcardTypeArgument() {} @Override - public void accept(TypeVisitor visitor) { + public void accept(TypeArgumentVisitor visitor) { visitor.visit(this); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java index 83978654..1dab2925 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java @@ -10,7 +10,9 @@ import org.jd.core.v1.model.javasyntax.declaration.BaseMemberDeclaration; import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; import org.jd.core.v1.model.javasyntax.declaration.TypeDeclaration; +import org.jd.core.v1.model.javasyntax.expression.FieldReferenceExpression; import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.TypeArgument; import org.jd.core.v1.util.DefaultList; import java.util.Collections; @@ -25,15 +27,14 @@ public class ClassFileBodyDeclaration extends BodyDeclaration implements ClassFi protected Map innerTypeMap = Collections.emptyMap(); protected int firstLineNumber; protected ObjectType outerType; - protected DefaultList outerLocalVariableNames; + protected DefaultList syntheticInnerFieldNames; + protected Map> syntheticInnerFieldNameToSyntheticInnerFieldReferences; protected ClassFileBodyDeclaration outerBodyDeclaration; + protected Map bindings; - public ClassFileBodyDeclaration(String internalTypeName) { - super(internalTypeName, null); - } - - public ClassFileBodyDeclaration(String internalTypeName, ClassFileBodyDeclaration outerBodyDeclaration) { + public ClassFileBodyDeclaration(String internalTypeName, Map bindings, ClassFileBodyDeclaration outerBodyDeclaration) { super(internalTypeName, null); + this.bindings = bindings; this.outerBodyDeclaration = outerBodyDeclaration; } @@ -123,18 +124,30 @@ public void setOuterType(ObjectType outerType) { this.outerType = outerType; } - public DefaultList getOuterLocalVariableNames() { - return outerLocalVariableNames; + public DefaultList getSyntheticInnerFieldNames() { + return syntheticInnerFieldNames; + } + + public void setSyntheticInnerFieldNames(DefaultList syntheticInnerFieldNames) { + this.syntheticInnerFieldNames = syntheticInnerFieldNames; } - public void setOuterLocalVariableNames(DefaultList outerLocalVariableNames) { - this.outerLocalVariableNames = outerLocalVariableNames; + public Map> getSyntheticInnerFieldNameToSyntheticInnerFieldReferences() { + return syntheticInnerFieldNameToSyntheticInnerFieldReferences; + } + + public void setSyntheticInnerFieldNameToSyntheticInnerFieldReferences(Map> map) { + this.syntheticInnerFieldNameToSyntheticInnerFieldReferences = map; } public ClassFileBodyDeclaration getOuterBodyDeclaration() { return outerBodyDeclaration; } + public Map getBindings() { + return bindings; + } + @Override public String toString() { return "ClassFileBodyDeclaration{firstLineNumber=" + firstLineNumber + "}"; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java index 4bfc009f..16184dd6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java @@ -12,6 +12,7 @@ import org.jd.core.v1.model.javasyntax.declaration.BaseFormalParameter; import org.jd.core.v1.model.javasyntax.statement.BaseStatement; import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; public interface ClassFileConstructorOrMethodDeclaration extends ClassFileMemberDeclaration { @@ -22,6 +23,8 @@ public interface ClassFileConstructorOrMethodDeclaration extends ClassFileMember Method getMethod(); + BaseTypeParameter getTypeParameters(); + BaseType getParameterTypes(); Type getReturnedType(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java index 44132a07..e5be2da5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java @@ -13,6 +13,7 @@ import org.jd.core.v1.model.javasyntax.declaration.StaticInitializerDeclaration; import org.jd.core.v1.model.javasyntax.statement.BaseStatement; import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; public class ClassFileStaticInitializerDeclaration extends StaticInitializerDeclaration implements ClassFileConstructorOrMethodDeclaration { @@ -51,6 +52,11 @@ public ClassFile getClassFile() { @Override public Method getMethod() { return method; } + @Override + public BaseTypeParameter getTypeParameters() { + return null; + } + @Override public BaseType getParameterTypes() { return null; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java index ea4a704b..302ec51e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java @@ -13,17 +13,27 @@ import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeParametersToTypeArgumentsBinder; public class ClassFileMethodInvocationExpression extends MethodInvocationExpression { protected BaseTypeParameter typeParameters; protected BaseType parameterTypes; + protected TypeParametersToTypeArgumentsBinder binder; - public ClassFileMethodInvocationExpression(int lineNumber, BaseTypeParameter typeParameters, Type type, Expression expression, String internalTypeName, String name, String descriptor, BaseType parameterTypes, BaseExpression parameters) { + public ClassFileMethodInvocationExpression( + TypeParametersToTypeArgumentsBinder binder, + int lineNumber, BaseTypeParameter typeParameters, Type type, Expression expression, + String internalTypeName, String name, String descriptor, BaseType parameterTypes, BaseExpression parameters) { super(lineNumber, type, expression, internalTypeName, name, descriptor, parameters); + this.binder = binder; this.typeParameters = typeParameters; this.parameterTypes = parameterTypes; } + public TypeParametersToTypeArgumentsBinder getBinder() { + return binder; + } + public BaseTypeParameter getTypeParameters() { return typeParameters; } @@ -31,4 +41,8 @@ public BaseTypeParameter getTypeParameters() { public BaseType getParameterTypes() { return parameterTypes; } + + public void setParameterTypes(BaseType parameterTypes) { + this.parameterTypes = parameterTypes; + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java index f79d6d6b..1e2df12e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java @@ -28,9 +28,18 @@ public BaseType getParameterTypes() { return parameterTypes; } + public void setParameterTypes(BaseType parameterTypes) { + this.parameterTypes = parameterTypes; + } + public void set(String descriptor, BaseType parameterTypes, BaseExpression parameters) { this.descriptor = descriptor; this.parameterTypes = parameterTypes; this.parameters = parameters; } + + @Override + public String toString() { + return "ClassFileNewExpression{new " + type + "}"; + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index e8077f4d..ae47b590 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -16,6 +16,7 @@ import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.LocalVariableMaker; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchUndeclaredLocalVariableVisitor; import org.jd.core.v1.util.DefaultList; @@ -76,7 +77,7 @@ public void setExceptionLocalVariable(AbstractLocalVariable exceptionLocalVariab this.exceptionLocalVariable = exceptionLocalVariable; } - public void mergeLocalVariable(AbstractLocalVariable lv) { + public void mergeLocalVariable(LocalVariableMaker localVariableMaker, AbstractLocalVariable lv) { int index = lv.getIndex(); AbstractLocalVariable alvToMerge; @@ -93,7 +94,7 @@ public void mergeLocalVariable(AbstractLocalVariable lv) { if (alvToMerge == null) { if (children != null) { for (Frame frame : children) { - frame.mergeLocalVariable(lv); + frame.mergeLocalVariable(localVariableMaker, lv); } } } else if (lv != alvToMerge) { @@ -104,22 +105,22 @@ public void mergeLocalVariable(AbstractLocalVariable lv) { lv.getReferences().addAll(alvToMerge.getReferences()); lv.setFromOffset(alvToMerge.getFromOffset()); - if (!lv.isAssignableFrom(alvToMerge)) { + if (!lv.isAssignableFrom(alvToMerge) && !localVariableMaker.isCompatible(lv, alvToMerge.getType())) { Type type = lv.getType(); Type alvToMergeType = alvToMerge.getType(); assert (type.isPrimitive() == alvToMergeType.isPrimitive()) && (type.isObject() == alvToMergeType.isObject()) && (type.isGeneric() == alvToMergeType.isGeneric()) : "Frame.mergeLocalVariable(lv) : merge local variable failed"; if (type.isPrimitive()) { - if (alvToMerge.isAssignableFrom(lv)) { + if (alvToMerge.isAssignableFrom(lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { ((PrimitiveLocalVariable)lv).setType((PrimitiveType)alvToMergeType); - } else if (!lv.isAssignableFrom(alvToMerge)) { + } else { ((PrimitiveLocalVariable)lv).setType(PrimitiveType.TYPE_INT); } } else if (type.isObject()) { - if (alvToMerge.isAssignableFrom(lv)) { + if (alvToMerge.isAssignableFrom(lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { ((ObjectLocalVariable)lv).setType(alvToMergeType); - } else if (!lv.isAssignableFrom(alvToMerge)) { + } else { int dimension = Math.max(lv.getDimension(), alvToMerge.getDimension()); ((ObjectLocalVariable)lv).setType(ObjectType.TYPE_OBJECT.createType(dimension)); } @@ -382,8 +383,8 @@ protected void createInlineDeclarations( splitMultiAssignment(Integer.MAX_VALUE, undeclaredLocalVariablesInStatement, expressions, boe); iterator.remove(); - for (BinaryOperatorExpression exp : (List)expressions) { - iterator.add(newDeclarationStatement(undeclaredLocalVariables, undeclaredLocalVariablesInStatement, exp)); + for (Expression exp : expressions) { + iterator.add(newDeclarationStatement(undeclaredLocalVariables, undeclaredLocalVariablesInStatement, (BinaryOperatorExpression)exp)); } if (expressions.isEmpty()) { @@ -434,9 +435,17 @@ protected LocalVariableDeclarationStatement newDeclarationStatement( localVariable.setDeclared(true); Type type = localVariable.getType(); - VariableInitializer variableInitializer = (boe.getRightExpression().getClass() == NewInitializedArray.class) ? - ((NewInitializedArray)boe.getRightExpression()).getArrayInitializer() : - new ExpressionVariableInitializer(boe.getRightExpression()); + VariableInitializer variableInitializer; + + if (boe.getRightExpression().getClass() == NewInitializedArray.class) { + if (type.isObject() && (((ObjectType)type).getTypeArguments() != null)) { + variableInitializer = new ExpressionVariableInitializer(boe.getRightExpression()); + } else { + variableInitializer = ((NewInitializedArray) boe.getRightExpression()).getArrayInitializer(); + } + } else { + variableInitializer = new ExpressionVariableInitializer(boe.getRightExpression()); + } return new LocalVariableDeclarationStatement(type, new LocalVariableDeclarator(boe.getLineNumber(), reference.getName(), variableInitializer)); } @@ -448,18 +457,18 @@ protected void createInlineDeclarations( BaseExpression init = fs.getInit(); if (init != null) { - Expressions expressions = new Expressions(); + Expressions expressions = new Expressions(); int toOffset = fs.getToOffset(); if (init.isList()) { - for (Expression exp : init.getList()) { + for (Expression exp : init) { splitMultiAssignment(toOffset, undeclaredLocalVariablesInStatement, expressions, exp); if (expressions.isEmpty()) { expressions.add(exp); } } } else { - splitMultiAssignment(toOffset, undeclaredLocalVariablesInStatement, expressions, (Expression)init); + splitMultiAssignment(toOffset, undeclaredLocalVariablesInStatement, expressions, init.getFirst()); if (expressions.isEmpty()) { expressions.add(init.getFirst()); } @@ -704,7 +713,7 @@ protected LocalVariableDeclarators createDeclarators2(DefaultList
@@ -66,7 +71,7 @@ public void process(Message message) throws Exception { protected ClassFileInterfaceDeclaration convertInterfaceDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); - ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); + ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, typeTypes.typeParameters, outerClassFileBodyDeclaration); return new ClassFileInterfaceDeclaration( annotationReferences, classFile.getAccessFlags(), @@ -77,7 +82,7 @@ protected ClassFileInterfaceDeclaration convertInterfaceDeclaration(TypeMaker pa protected ClassFileEnumDeclaration convertEnumDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); - ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); + ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, typeTypes.typeParameters, outerClassFileBodyDeclaration); return new ClassFileEnumDeclaration( annotationReferences, classFile.getAccessFlags(), @@ -88,7 +93,7 @@ protected ClassFileEnumDeclaration convertEnumDeclaration(TypeMaker parser, Anno protected ClassFileAnnotationDeclaration convertAnnotationDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); - ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); + ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, typeTypes.typeParameters, outerClassFileBodyDeclaration); return new ClassFileAnnotationDeclaration( annotationReferences, classFile.getAccessFlags(), @@ -99,7 +104,7 @@ protected ClassFileAnnotationDeclaration convertAnnotationDeclaration(TypeMaker protected ClassFileClassDeclaration convertClassDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { BaseAnnotationReference annotationReferences = convertAnnotationReferences(converter, classFile); TypeMaker.TypeTypes typeTypes = parser.parseClassFileSignature(classFile); - ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, outerClassFileBodyDeclaration); + ClassFileBodyDeclaration bodyDeclaration = convertBodyDeclaration(parser, converter, classFile, typeTypes.typeParameters, outerClassFileBodyDeclaration); return new ClassFileClassDeclaration( annotationReferences, classFile.getAccessFlags(), @@ -108,8 +113,8 @@ protected ClassFileClassDeclaration convertClassDeclaration(TypeMaker parser, An typeTypes.interfaces, bodyDeclaration); } - protected ClassFileBodyDeclaration convertBodyDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { - ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile.getInternalTypeName(), outerClassFileBodyDeclaration); + protected ClassFileBodyDeclaration convertBodyDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, BaseTypeParameter typeParameters, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile.getInternalTypeName(), createBindings(classFile, typeParameters, outerClassFileBodyDeclaration), outerClassFileBodyDeclaration); bodyDeclaration.setFieldDeclarations(convertFields(parser, converter, classFile)); bodyDeclaration.setMethodDeclarations(convertMethods(parser, converter, bodyDeclaration, classFile)); @@ -118,6 +123,34 @@ protected ClassFileBodyDeclaration convertBodyDeclaration(TypeMaker parser, Anno return bodyDeclaration; } + protected Map createBindings(ClassFile classFile, BaseTypeParameter typeParameters, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + if (typeParameters == null) { + if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null) && (outerClassFileBodyDeclaration.getBindings() != null)) { + return outerClassFileBodyDeclaration.getBindings(); + } else { + return Collections.emptyMap(); + } + } else { + HashMap bindings = new HashMap<>(); + + if (typeParameters.isList()) { + for (TypeParameter tp : typeParameters) { + String identifier = tp.getIdentifier(); + bindings.put(identifier, new GenericType(identifier)); + } + } else { + String identifier = typeParameters.getFirst().getIdentifier(); + bindings.put(identifier, new GenericType(identifier)); + } + + if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null) && (outerClassFileBodyDeclaration.getBindings() != null)) { + bindings.putAll(outerClassFileBodyDeclaration.getBindings()); + } + + return bindings; + } + } + protected List convertFields(TypeMaker parser, AnnotationConverter converter, ClassFile classFile) { Field[] fields = classFile.getFields(); @@ -168,7 +201,7 @@ protected List convertMethods(TypeMaker } if ("".equals(name)) { - TypeMaker.MethodTypes methodTypes = parser.parseConstructorSignature(classFile, method); + TypeMaker.MethodTypes methodTypes = parser.parseMethodSignature(classFile, method); list.add(new ClassFileConstructorDeclaration( bodyDeclaration, classFile, method, annotationReferences, methodTypes.typeParameters, methodTypes.parameterTypes, methodTypes.exceptions, firstLineNumber)); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AggregateFieldsUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AggregateFieldsUtil.java index f94746ec..de8b58b7 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AggregateFieldsUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/AggregateFieldsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,6 +7,7 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; +import org.jd.core.v1.model.javasyntax.declaration.BaseFieldDeclarator; import org.jd.core.v1.model.javasyntax.declaration.FieldDeclarators; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFieldDeclaration; @@ -63,10 +64,22 @@ protected static void aggregate(List fields, ClassFil int length = lastIndex - firstIndex; FieldDeclarators declarators = new FieldDeclarators(length); - declarators.add(firstField.getFieldDeclarators()); + BaseFieldDeclarator bfd = firstField.getFieldDeclarators(); + + if (bfd.isList()) { + declarators.addAll(bfd.getList()); + } else { + declarators.add(bfd.getFirst()); + } for (ClassFileFieldDeclaration f : sublist) { - declarators.add(f.getFieldDeclarators()); + bfd = f.getFieldDeclarators(); + + if (bfd.isList()) { + declarators.addAll(bfd.getList()); + } else { + declarators.add(bfd.getFirst()); + } } firstField.setFieldDeclarators(declarators); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index d6762f1b..fab08bb4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -31,42 +31,45 @@ import org.jd.core.v1.util.DefaultList; import org.jd.core.v1.util.DefaultStack; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; +import java.util.*; -import static org.jd.core.v1.model.classfile.Constants.ACC_STATIC; import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_PRIVATE; +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_STATIC; import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_SYNTHETIC; import static org.jd.core.v1.model.javasyntax.statement.ReturnStatement.RETURN; -import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; public class ByteCodeParser { private static final JsrReturnAddressExpression JSR_RETURN_ADDRESS_EXPRESSION = new JsrReturnAddressExpression(); + private MemberVisitor memberVisitor = new MemberVisitor(); + private SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); + private TypeMaker typeMaker; private LocalVariableMaker localVariableMaker; private ClassFile classFile; private String internalTypeName; + private TypeParametersToTypeArgumentsBinder typeParametersToTypeArgumentsBinder; private AttributeBootstrapMethods attributeBootstrapMethods; private ClassFileBodyDeclaration bodyDeclaration; - private MemberVisitor memberVisitor = new MemberVisitor(); - private SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); + private Type returnedType; - public ByteCodeParser(TypeMaker typeMaker, LocalVariableMaker localVariableMaker, ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration) { + public ByteCodeParser( + TypeMaker typeMaker, LocalVariableMaker localVariableMaker, ClassFile classFile, + ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; this.classFile = classFile; this.internalTypeName = classFile.getInternalTypeName(); + this.typeParametersToTypeArgumentsBinder = new TypeParametersToTypeArgumentsBinder(typeMaker, this.internalTypeName, bodyDeclaration, comd); this.attributeBootstrapMethods = classFile.getAttribute("BootstrapMethods"); this.bodyDeclaration = bodyDeclaration; + this.returnedType = comd.getReturnedType(); } @SuppressWarnings("unchecked") - public void parse(BasicBlock basicBlock, Statements statements, DefaultStack stack) { + public void parse(BasicBlock basicBlock, Statements statements, DefaultStack stack) { ControlFlowGraph cfg = basicBlock.getControlFlowGraph(); int fromOffset = basicBlock.getFromOffset(); int toOffset = basicBlock.getToOffset(); @@ -137,8 +140,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau case 25: // ALOAD i = code[++offset] & 255; localVariable = localVariableMaker.getLocalVariable(i, offset); - - if ((i == 0) && ((method.getAccessFlags() & ACC_STATIC) == 0)) { + if ((i == 0) && ((method.getAccessFlags() & FLAG_STATIC) == 0)) { stack.push(new ThisExpression(lineNumber, localVariable.getType())); } else { stack.push(new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable)); @@ -162,8 +164,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau break; case 42: // ALOAD_0 localVariable = localVariableMaker.getLocalVariable(0, offset); - - if ((method.getAccessFlags() & ACC_STATIC) == 0) { + if ((method.getAccessFlags() & FLAG_STATIC) == 0) { stack.push(new ThisExpression(lineNumber, localVariable.getType())); } else { stack.push(new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable)); @@ -236,7 +237,9 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau indexRef = stack.pop(); arrayRef = stack.pop(); type1 = arrayRef.getType(); - statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, type1.createType(type1.getDimension()>0 ? type1.getDimension()-1 : 0), new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); + type2 = type1.createType(type1.getDimension()>0 ? type1.getDimension()-1 : 0); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(type2, valueRef); + statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, type2, new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); break; case 84: // BASTORE valueRef = stack.pop(); @@ -260,6 +263,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau expression1 = stack.pop(); Class clazz = expression1.getClass(); if ((clazz != ClassFileLocalVariableReferenceExpression.class) && (clazz != FieldReferenceExpression.class)) { + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(TYPE_VOID, expression1); statements.add(new ExpressionStatement(expression1)); } break; @@ -718,14 +722,11 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - TypeMaker.MethodTypes methodTypes = typeMaker.makeMethodTypes(ot, name, descriptor); + TypeMaker.MethodTypes methodTypes = typeMaker.makeMethodTypes(ot.getInternalName(), name, descriptor); BaseExpression parameters = extractParametersFromStack(statements, stack, methodTypes.parameterTypes); if (opcode == 184) { // INVOKESTATIC - Type returnedType = bindParameterTypesWithArgumentType(ot, methodTypes.returnedType); - BaseType parameterTypes = bindParameterTypesWithArgumentTypes(ot, methodTypes.parameterTypes); - parameters = prepareParameters(parameters, parameterTypes); - expression1 = new ClassFileMethodInvocationExpression(lineNumber, methodTypes.typeParameters, returnedType, new ObjectTypeReferenceExpression(lineNumber, ot), typeName, name, descriptor, parameterTypes, parameters); + expression1 = typeParametersToTypeArgumentsBinder.newMethodInvocationExpression(lineNumber, new ObjectTypeReferenceExpression(lineNumber, ot), ot, name, descriptor, methodTypes, parameters); if (TYPE_VOID.equals(methodTypes.returnedType)) { statements.add(new ExpressionStatement(expression1)); } else { @@ -733,40 +734,43 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau } } else { expression1 = stack.pop(); - Type returnedType = bindParameterTypesWithArgumentType(ot, methodTypes.returnedType); - BaseType parameterTypes = bindParameterTypesWithArgumentTypes(ot, methodTypes.parameterTypes); - //BaseType parameterTypes = getRawType(expression1, ot, methodTypes.parameterTypes); - parameters = prepareParameters(parameters, parameterTypes); if (expression1.getClass() == ClassFileLocalVariableReferenceExpression.class) { ((ClassFileLocalVariableReferenceExpression)expression1).getLocalVariable().typeOnLeft(ot); } if (opcode == 185) { // INVOKEINTERFACE offset += 2; // Skip 'count' and one byte } - if (TYPE_VOID.equals(returnedType)) { + if (TYPE_VOID.equals(methodTypes.returnedType)) { if ((opcode == 183) && // INVOKESPECIAL "".equals(name)) { if (expression1.getClass() == ClassFileNewExpression.class) { - ((ClassFileNewExpression)expression1).set(descriptor, parameterTypes, parameters); + typeParametersToTypeArgumentsBinder.updateNewExpression(expression1, descriptor, methodTypes, parameters); } else if (ot.getDescriptor().equals(expression1.getType().getDescriptor())) { - statements.add(new ExpressionStatement(new ClassFileConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); + statements.add(new ExpressionStatement(typeParametersToTypeArgumentsBinder.newConstructorInvocationExpression( + lineNumber, ot, descriptor, methodTypes, parameters))); } else { - statements.add(new ExpressionStatement(new ClassFileSuperConstructorInvocationExpression(lineNumber, ot, descriptor, parameterTypes, parameters))); + statements.add(new ExpressionStatement(typeParametersToTypeArgumentsBinder.newSuperConstructorInvocationExpression( + lineNumber, ot, descriptor, methodTypes, parameters))); } } else { - statements.add(new ExpressionStatement(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.typeParameters, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters))); + expression1 = typeParametersToTypeArgumentsBinder.newMethodInvocationExpression( + lineNumber, getMethodInstanceReference(expression1, ot, name, descriptor), ot, name, descriptor, methodTypes, parameters); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(TYPE_VOID, expression1); + statements.add(new ExpressionStatement(expression1)); } } else { - if ((opcode == 182) && // INVOKEVIRTUAL - "toString".equals(name) && "()Ljava/lang/String;".equals(descriptor)) { - typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); - if ("java/lang/StringBuilder".equals(typeName) || "java/lang/StringBuffer".equals(typeName)) { - stack.push(StringConcatenationUtil.create(expression1, lineNumber, typeName)); - break; + if (opcode == 182) { // INVOKEVIRTUAL + if ("toString".equals(name) && "()Ljava/lang/String;".equals(descriptor)) { + typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); + if ("java/lang/StringBuilder".equals(typeName) || "java/lang/StringBuffer".equals(typeName)) { + stack.push(StringConcatenationUtil.create(expression1, lineNumber, typeName)); + break; + } } } - stack.push(new ClassFileMethodInvocationExpression(lineNumber, methodTypes.typeParameters, returnedType, getMethodInstanceReference(expression1, ot, name, descriptor), typeName, name, descriptor, parameterTypes, parameters)); + stack.push(typeParametersToTypeArgumentsBinder.newMethodInvocationExpression( + lineNumber, getMethodInstanceReference(expression1, ot, name, descriptor), ot, name, descriptor, methodTypes, parameters)); } } break; @@ -802,6 +806,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau typeName = constants.getConstantTypeName( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); type1 = typeMaker.makeFromDescriptorOrInternalTypeName(typeName); expression1 = stack.pop(); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(type1, expression1); if (expression1.getClass() == CastExpression.class) { // Skip double cast ((CastExpression)expression1).setType(type1); @@ -934,176 +939,7 @@ private BaseExpression extractParametersFromStack(Statements statements, Default } } - private Type getRawType(Type type) { - if (type.isGeneric()) { - return TYPE_OBJECT.createType(type.getDimension()); - } - - if (type.isObject()) { - ObjectType ot = (ObjectType)type; - - if (ot.getTypeArguments() != null) { - return ot.createType(null); - } - } - - return type; - } - - private Type bindParameterTypesWithArgumentType(ObjectType objectType, Type type) { - if (type == null) { - return null; - } - - if (objectType.getInternalName().equals(internalTypeName)) { - return type; - } - - return getRawType(type); - } - - private BaseType bindParameterTypesWithArgumentTypes(ObjectType objectType, BaseType parameterTypes) { - if (parameterTypes == null) { - return null; - } - - if (objectType.getInternalName().equals(internalTypeName)) { - return parameterTypes; - } - - switch (parameterTypes.size()) { - case 0: - return null; - case 1: - return getRawType(parameterTypes.getFirst()); - default: - DefaultList list = parameterTypes.getList(); - int count = list.size(); - - for (int i=0; i types = new Types<>(list); - for (i=0; i bind = new HashMap<>(); - - switch (expressionTypeArguments.typeArgumentSize()) { - case 0: - break; - case 1: - bind.put(typeParameters.getFirst(), expressionTypeArguments.getTypeArgumentFirst()); - break; - default: - Iterator typeParameterIterator = typeParameters.getList().iterator(); - Iterator typeArgumentIterator = expressionTypeArguments.getTypeArgumentList().iterator(); - - while (typeParameterIterator.hasNext()) { - bind.put(typeParameterIterator.next(), typeArgumentIterator.next()); - } - break; - } - - // Replace - switch (parameterTypes.size()) { - case 0: - return parameterTypes; - case 1: - Type parameterType = parameterTypes.getFirst(); - TypeArgument typeArgument = bind.get(parameterType); - - if (typeArgument == null) { - return parameterType; - } else { - return (typeArgument instanceof Type) ? (Type)typeArgument : TYPE_OBJECT; - } - default: - DefaultList list = parameterTypes.getList(); - int count = list.size(); - - for (int i=0; i types = new Types<>(list); - for (i=0; i 1) { - DefaultList parameters = parameterExpressions.getList(); - DefaultList types = parameterTypes.getList(); - - for (int i=0; i statements, Expression parameter) { + private static Expression checkIfLastStatementIsAMultiAssignment(Statements statements, Expression parameter) { if (!statements.isEmpty()) { Statement lastStatement = statements.getLast(); @@ -1143,6 +979,14 @@ private AbstractLocalVariable getLocalVariableInAssignment(int index, int offset return localVariableMaker.getLocalVariableInAssignment(index, offset, valueType); } else { + if (valueClass == CastExpression.class) { + Type type = ((CastExpression)value).getExpression().getType(); + + if (type.isGeneric()) { + return localVariableMaker.getLocalVariableInCastAssignment(index, offset, valueType, type); + } + } + return localVariableMaker.getLocalVariableInAssignment(index, offset, valueType); } } @@ -1218,7 +1062,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in } } - private static void parseILOAD(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable) { + private static void parseILOAD(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable) { if (! statements.isEmpty()) { Statement statement = statements.getLast(); @@ -1249,6 +1093,8 @@ private static void parseILOAD(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(vre.getType(), valueRef); + if ((valueRef.getLineNumber() == lineNumber) && (valueRef.getClass() == BinaryOperatorExpression.class)) { BinaryOperatorExpression boe = (BinaryOperatorExpression)valueRef; @@ -1347,6 +1193,8 @@ private void parsePUT(Statements statements, DefaultStack stack, int valueRef = NewArrayMaker.make(statements, (NewArray)valueRef); } + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(fr.getType(), valueRef); + if ((valueRef.getLineNumber() == lineNumber) && (valueRef.getClass() == BinaryOperatorExpression.class)) { BinaryOperatorExpression boe = (BinaryOperatorExpression)valueRef; @@ -1425,7 +1273,7 @@ private void parsePUT(Statements statements, DefaultStack stack, int createAssignment(statements, stack, lineNumber, fr, valueRef); } - private void parseInvokeDynamic(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { + private void parseInvokeDynamic(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { // Remove previous 'getClass()' or cast if exists if (! statements.isEmpty()) { Statement last = statements.getLast(); @@ -1452,8 +1300,6 @@ private void parseInvokeDynamic(Statements statements, DefaultStack prepareLambdaParameters(BaseFormalParameter formalPa private static BaseStatement prepareLambdaStatements(BaseStatement baseStatement) { if ((baseStatement != null) && baseStatement.isList()) { - DefaultList statements = baseStatement.getList(); - - if (statements.size() == 1) { - Statement statement = statements.getFirst(); + if (baseStatement.size() == 1) { + Statement statement = baseStatement.getFirst(); if (statement.getClass() == ReturnExpressionStatement.class) { return new LambdaExpressionStatement(((ReturnExpressionStatement)statement).getExpression()); @@ -1584,8 +1428,11 @@ private static boolean isNegativeOne(Expression expression) { return ((expression.getClass() == DoubleConstantExpression.class) && ((DoubleConstantExpression)expression).getValue() == -1.0D); } - private void parseASTORE(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { + private void parseASTORE(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); + + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(vre.getType(), valueRef); + Expression oldValueRef = valueRef; if (valueRef.getClass() == NewArray.class) { @@ -1600,7 +1447,7 @@ private void parseASTORE(Statements statements, DefaultStack statements, DefaultStack stack, int lineNumber, Expression leftExpression, Expression rightExpression) { + private void createAssignment(Statements statements, DefaultStack stack, int lineNumber, Expression leftExpression, Expression rightExpression) { if (!stack.isEmpty() && (stack.peek() == rightExpression)) { stack.push(new BinaryOperatorExpression(lineNumber, leftExpression.getType(), leftExpression, "=", stack.pop(), 16)); return; @@ -1765,13 +1612,15 @@ private static void parseIF(DefaultStack stack, int lineNumber, Basi } @SuppressWarnings("unchecked") - private void parseXRETURN(Statements statements, DefaultStack stack, int lineNumber) { + private void parseXRETURN(Statements statements, DefaultStack stack, int lineNumber) { Expression valueRef = stack.pop(); if (valueRef.getClass() == NewArray.class) { valueRef = NewArrayMaker.make(statements, (NewArray)valueRef); } + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(returnedType, valueRef); + if (lineNumber > valueRef.getLineNumber()) { lineNumber = valueRef.getLineNumber(); } @@ -1827,9 +1676,9 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan ObjectType ot = typeMaker.makeFromInternalTypeName(typeName); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.makeFieldType(ot, name, descriptor); + Type type = typeMaker.makeFieldType(ot.getInternalName(), name, descriptor); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); - stack.push(new FieldReferenceExpression(lineNumber, type, objectRef, typeName, name, descriptor)); + stack.push(typeParametersToTypeArgumentsBinder.newFieldReferenceExpression(lineNumber, type, objectRef, ot, name, descriptor)); } private void parsePutStatic(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { @@ -1839,10 +1688,10 @@ private void parsePutStatic(Statements statements, DefaultStack stac ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.makeFieldType(ot, name, descriptor); + Type type = typeMaker.makeFieldType(ot.getInternalName(), name, descriptor); Expression valueRef = stack.pop(); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); - FieldReferenceExpression fieldRef = new FieldReferenceExpression(lineNumber, type, objectRef, typeName, name, descriptor); + FieldReferenceExpression fieldRef = typeParametersToTypeArgumentsBinder.newFieldReferenceExpression(lineNumber, type, objectRef, ot, name, descriptor); parsePUT(statements, stack, lineNumber, fieldRef, valueRef); } @@ -1853,9 +1702,10 @@ private void parseGetField(DefaultStack stack, ConstantPool constant ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.makeFieldType(ot, name, descriptor); + Type type = typeMaker.makeFieldType(ot.getInternalName(), name, descriptor); Expression objectRef = stack.pop(); - stack.push(new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor)); + stack.push(typeParametersToTypeArgumentsBinder.newFieldReferenceExpression( + lineNumber, type, getFieldInstanceReference(objectRef, ot, name), ot, name, descriptor)); } private void parsePutField(Statements statements, DefaultStack stack, ConstantPool constants, int lineNumber, int index) { @@ -1865,10 +1715,11 @@ private void parsePutField(Statements statements, DefaultStack stack ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - Type type = typeMaker.makeFieldType(ot, name, descriptor); + Type type = typeMaker.makeFieldType(ot.getInternalName(), name, descriptor); Expression valueRef = stack.pop(); Expression objectRef = stack.pop(); - FieldReferenceExpression fieldRef = new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor); + FieldReferenceExpression fieldRef = typeParametersToTypeArgumentsBinder.newFieldReferenceExpression( + lineNumber, type, getFieldInstanceReference(objectRef, ot, name), ot, name, descriptor); parsePUT(statements, stack, lineNumber, fieldRef, valueRef); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index df1576b8..4ba84e46 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -43,9 +43,9 @@ public class LocalVariableMaker { protected CreateLocalVariableVisitor createLocalVariableVisitor; @SuppressWarnings("unchecked") - public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDeclaration comdwln, boolean constructor, BaseType parameterTypes) { - ClassFile classFile = comdwln.getClassFile(); - Method method = comdwln.getMethod(); + public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDeclaration comd, boolean constructor, BaseType parameterTypes) { + ClassFile classFile = comd.getClassFile(); + Method method = comd.getMethod(); this.typeMaker = typeMaker; this.createParameterVisitor = new CreateParameterVisitor(typeMaker); @@ -78,7 +78,7 @@ public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDecla if (parameterTypes != null) { if (parameterTypes.isList()) { - for (Type type : parameterTypes.getList()) { + for (Type type : parameterTypes) { type.accept(populateBlackListNamesVisitor); } } else { @@ -305,7 +305,7 @@ public AbstractLocalVariable getLocalVariable(int index, int offset) { } } else if (lv.getFrame() != currentFrame) { Frame frame = searchCommonParentFrame(lv.getFrame(), currentFrame); - frame.mergeLocalVariable(lv); + frame.mergeLocalVariable(this, lv); if (lv.getFrame() != frame) { lv.getFrame().removeLocalVariable(lv); @@ -336,7 +336,7 @@ protected AbstractLocalVariable searchLocalVariable(int index, int offset) { return lv; } - protected boolean isCompatible(AbstractLocalVariable lv, Type valueType) { + public boolean isCompatible(AbstractLocalVariable lv, Type valueType) { if (valueType.isObject() && (lv.getType().getDimension() == valueType.getDimension())) { ObjectType valueObjectType = (ObjectType) valueType; @@ -393,6 +393,33 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, return lv; } + public AbstractLocalVariable getLocalVariableInCastAssignment(int index, int offset, Type castType, Type valueType) { + AbstractLocalVariable lv = searchLocalVariable(index, offset); + + if (lv == null) { + // Create a new local variable + createLocalVariableVisitor.init(index, offset); + valueType.accept(createLocalVariableVisitor); + lv = createLocalVariableVisitor.getLocalVariable(); + } else if (lv.isAssignableFrom(castType) || isCompatible(lv, castType)) { + // Assignable, reduce type + lv.typeOnRight(castType); + } else if (lv.isAssignableFrom(valueType) || isCompatible(lv, valueType)) { + // Assignable, reduce type + lv.typeOnRight(valueType); + } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueType)) { + // Not assignable -> Create a new local variable + createLocalVariableVisitor.init(index, offset); + valueType.accept(createLocalVariableVisitor); + lv = createLocalVariableVisitor.getLocalVariable(); + } + + lv.setToOffset(offset); + store(lv); + + return lv; + } + public AbstractLocalVariable getLocalVariableInNullAssignment(int index, int offset, Type valueType) { AbstractLocalVariable lv = searchLocalVariable(index, offset); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index bd0bc0c6..e23b12c8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -9,6 +9,7 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.GenericType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; @@ -18,6 +19,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForEachStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.GenericLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.ObjectLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.CreateTypeFromTypeArgumentVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.RemoveLastContinueStatementVisitor; @@ -33,7 +35,7 @@ public class LoopStatementMaker { protected static final RemoveLastContinueStatementVisitor REMOVE_LAST_CONTINUE_STATEMENT_VISITOR = new RemoveLastContinueStatementVisitor(); - public static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements, Statements jumps) { + public static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements, Statements jumps) { Statement loop = makeLoop(localVariableMaker, loopBasicBlock, statements, condition, subStatements); int continueOffset = loopBasicBlock.getSub1().getFromOffset(); int breakOffset = loopBasicBlock.getNext().getFromOffset(); @@ -45,7 +47,7 @@ public static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlo return makeLabels(loopBasicBlock.getIndex(), continueOffset, breakOffset, loop, jumps); } - protected static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements) { + protected static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements) { subStatements.accept(REMOVE_LAST_CONTINUE_STATEMENT_VISITOR); Statement statement = makeForEachArray(localVariableMaker, statements, condition, subStatements); @@ -122,7 +124,7 @@ protected static Statement makeLoop(LocalVariableMaker localVariableMaker, Basic return new WhileStatement(condition, subStatements); } - public static Statement makeLoop(BasicBlock loopBasicBlock, Statements statements, Statements subStatements, Statements jumps) { + public static Statement makeLoop(BasicBlock loopBasicBlock, Statements statements, Statements subStatements, Statements jumps) { subStatements.accept(REMOVE_LAST_CONTINUE_STATEMENT_VISITOR); Statement loop = makeLoop(loopBasicBlock, statements, subStatements); @@ -136,7 +138,7 @@ public static Statement makeLoop(BasicBlock loopBasicBlock, Statements statements, Statements subStatements) { + protected static Statement makeLoop(BasicBlock loopBasicBlock, Statements statements, Statements subStatements) { int subStatementsSize = subStatements.size(); if ((subStatementsSize > 0) && (subStatements.getLast() == CONTINUE)) { @@ -173,7 +175,7 @@ protected static Statement makeLoop(BasicBlock loopBasicBlock, Statements 0) { // Populates 'update' - Expressions update = extractUpdate(subStatements, firstLineNumber); + Expressions update = extractUpdate(subStatements, firstLineNumber); if (update.size() > 0) { // Populates 'init' @@ -208,7 +210,7 @@ public static Statement makeDoWhileLoop(BasicBlock loopBasicBlock, BasicBlock la } @SuppressWarnings("unchecked") - protected static BaseExpression extractInit(Statements statements, int lineNumber) { + protected static BaseExpression extractInit(Statements statements, int lineNumber) { if (lineNumber > 0) { switch (statements.size()) { case 0: @@ -266,8 +268,8 @@ protected static BaseExpression extractInit(Statements statements, in } @SuppressWarnings("unchecked") - protected static Expressions extractUpdate(Statements statements, int firstLineNumber) { - Expressions update = new Expressions(); + protected static Expressions extractUpdate(Statements statements, int firstLineNumber) { + Expressions update = new Expressions(); ListIterator iterator = statements.listIterator(statements.size()); // Populates 'update' @@ -291,7 +293,7 @@ protected static Expressions extractUpdate(Statements statements, in return update; } - protected static Statement createForStatementWithoutLineNumber(BasicBlock basicBlock, Statements statements, Expression condition, Statements subStatements) { + protected static Statement createForStatementWithoutLineNumber(BasicBlock basicBlock, Statements statements, Expression condition, Statements subStatements) { if (!statements.isEmpty()) { Statement statement = statements.getLast(); @@ -342,7 +344,7 @@ protected static Statement createForStatementWithoutLineNumber(BasicBlock basicB return new WhileStatement(condition, subStatements); } - protected static Statement makeForEachArray(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { + protected static Statement makeForEachArray(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { if (condition == null) { return null; } @@ -508,6 +510,8 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake if (ObjectType.TYPE_OBJECT.equals(item.getType())) { ((ObjectLocalVariable)item).setType(type); + } else if (item.getType().isGeneric()) { + ((GenericLocalVariable)item).setType((GenericType)type); } else { item.typeOnRight(type); } @@ -519,7 +523,7 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake return new ClassFileForEachStatement(item, array, subStatements); } - protected static Statement makeForEachList(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { + protected static Statement makeForEachList(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { if (condition == null) { return null; } @@ -575,6 +579,10 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker Expression list = mie.getExpression(); + if (list.getClass() == CastExpression.class) { + list = ((CastExpression)list).getExpression(); + } + // String s = (String)i$.next(); Statement firstSubStatement = subStatements.get(0); @@ -633,7 +641,15 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker ObjectType listType = (ObjectType)list.getType(); - if (listType.getTypeArguments() != null) { + if (listType.getTypeArguments() == null) { + if (item.getType().isObject()) { + ObjectType ot = (ObjectType)item.getType(); + + if (ot.getTypeArguments() != null) { + TypeParametersToTypeArgumentsBinder.staticBindParameterTypesWithArgumentTypes(ot, list); + } + } + } else { CreateTypeFromTypeArgumentVisitor visitor2 = new CreateTypeFromTypeArgumentVisitor(); listType.getTypeArguments().accept(visitor2); Type type = visitor2.getType(); @@ -641,6 +657,8 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker if (type != null) { if (ObjectType.TYPE_OBJECT.equals(item.getType())) { ((ObjectLocalVariable)item).setType(type); + } else if (item.getType().isGeneric()) { + ((GenericLocalVariable)item).setType((GenericType)type); } else { item.typeOnRight(type); } @@ -653,12 +671,12 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker @SuppressWarnings("unchecked") protected static Statement makeLabels(int loopIndex, int continueOffset, int breakOffset, Statement loop, Statements jumps) { if (!jumps.isEmpty()) { - Iterator iterator = jumps.iterator(); + Iterator iterator = jumps.iterator(); String label = "label" + loopIndex; boolean createLabel = false; while (iterator.hasNext()) { - ClassFileBreakContinueStatement statement = iterator.next(); + ClassFileBreakContinueStatement statement = (ClassFileBreakContinueStatement)iterator.next(); int offset = statement.getOffset(); int targetOffset = statement.getTargetOffset(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java index 58a7d3b2..9c4e3a16 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -7,6 +7,7 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; +import org.jd.core.v1.model.javasyntax.declaration.MemberDeclaration; import org.jd.core.v1.model.javasyntax.declaration.MemberDeclarations; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMemberDeclaration; @@ -44,7 +45,7 @@ public static MemberDeclarations merge( return result; } - protected static void merge(List result, List members) { + protected static void merge(List result, List members) { if ((members != null) && !members.isEmpty()) { sort(members); @@ -68,7 +69,8 @@ protected static void merge(List result, List listLineNumber) break; resultIndex++; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/NewArrayMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/NewArrayMaker.java index fe9fa4c7..efc0f2f1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/NewArrayMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/NewArrayMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -24,7 +24,7 @@ public class NewArrayMaker { protected static final ArrayVariableInitializer EMPTY_ARRAY = new ArrayVariableInitializer(PrimitiveType.TYPE_VOID); @SuppressWarnings("unchecked") - public static Expression make(Statements statements, NewArray newArray) { + public static Expression make(Statements statements, NewArray newArray) { if (! statements.isEmpty()) { Statement statement = statements.getLast(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 4ffc98eb..b998b466 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -37,6 +37,8 @@ import java.util.*; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; +import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; public class StatementMaker { @@ -61,16 +63,16 @@ public class StatementMaker { public StatementMaker( TypeMaker typeMaker, LocalVariableMaker localVariableMaker, - ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration, Type returnedType) { + ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; this.majorVersion = classFile.getMajorVersion(); this.internalTypeName = classFile.getInternalTypeName(); this.bodyDeclaration = bodyDeclaration; - this.byteCodeParser = new ByteCodeParser(typeMaker, localVariableMaker, classFile, bodyDeclaration); + this.byteCodeParser = new ByteCodeParser(typeMaker, localVariableMaker, classFile, bodyDeclaration, comd); this.removeFinallyStatementsVisitor = new RemoveFinallyStatementsVisitor(localVariableMaker); this.removeBinaryOpReturnStatementsVisitor = new RemoveBinaryOpReturnStatementsVisitor(localVariableMaker); - this.updateIntegerConstantTypeVisitor = new UpdateIntegerConstantTypeVisitor(returnedType); + this.updateIntegerConstantTypeVisitor = new UpdateIntegerConstantTypeVisitor(comd.getReturnedType()); } public Statements make(ControlFlowGraph cfg) { @@ -260,8 +262,8 @@ protected void makeStatements(WatchDog watchdog, BasicBlock basicBlock, Statemen } } - protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, Statements updateStatements) { - Statements subStatements = makeSubStatements(watchdog, basicBlock, statements, jumps); + protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, Statements updateStatements) { + Statements subStatements = makeSubStatements(watchdog, basicBlock, statements, jumps); if (updateStatements != null) { subStatements.addAll(updateStatements); @@ -270,8 +272,8 @@ protected Statements makeSubStatements(WatchDog watchdog, BasicBlock return subStatements; } - protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { - Statements subStatements = new Statements<>(); + protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { + Statements subStatements = new Statements(); if (!statements.isEmpty() && (statements.getLast().getClass() == ClassFileMonitorEnterStatement.class)) { subStatements.add(statements.removeLast()); @@ -289,7 +291,7 @@ protected Statements makeSubStatements(WatchDog watchdog, BasicBlock return subStatements; } - protected Expression makeExpression(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { + protected Expression makeExpression(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { int initialStatementCount = statements.size(); makeStatements(watchdog, basicBlock, statements, jumps); @@ -325,7 +327,7 @@ protected Expression makeExpression(WatchDog watchdog, BasicBlock basicBlock, St } } - protected void parseSwitch(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { + protected void parseSwitch(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { parseByteCode(basicBlock, statements); List switchCases = basicBlock.getSwitchCases(); @@ -387,7 +389,7 @@ protected void parseSwitch(WatchDog watchdog, BasicBlock basicBlock, Statements< protected void parseTry(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, boolean jsr, boolean eclipse) { Statements tryStatements; DefaultList catchClauses = new DefaultList<>(); - Statements finallyStatements = null; + Statements finallyStatements = null; int assertStackSize = stack.size(); tryStatements = makeSubStatements(watchdog, basicBlock.getSub1(), statements, jumps); @@ -520,7 +522,7 @@ protected void removeExceptionReference(Statements catchStatements) { } } - protected void parseJSR(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { + protected void parseJSR(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { int statementCount = statements.size(); parseByteCode(basicBlock, statements); @@ -595,7 +597,8 @@ protected void parseIf(WatchDog watchdog, BasicBlock basicBlock, Statements stat if (cfres1.getLineNumber() == cfres2.getLineNumber()) { statements.subList(index-1, statements.size()).clear(); - statements.add(new ReturnExpressionStatement(new TernaryOperatorExpression(cfres1.getLineNumber(), cond, cfres1.getExpression(), cfres2.getExpression()))); + statements.add(new ReturnExpressionStatement(newTernaryOperatorExpression( + cfres1.getLineNumber(), cond, cfres1.getExpression(), cfres2.getExpression()))); } } } @@ -605,7 +608,7 @@ protected void parseIf(WatchDog watchdog, BasicBlock basicBlock, Statements stat @SuppressWarnings("unchecked") protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { BasicBlock sub1 = basicBlock.getSub1(); - Statements updateStatements = null; + Statements updateStatements = null; if ((sub1.getType() == TYPE_IF) && (sub1.getCondition() == END)) { updateStatements = makeSubStatements(watchdog, sub1.getNext(), statements, jumps); @@ -618,7 +621,8 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st if (ifBB.getNext() == LOOP_END) { // 'while' or 'for' loop makeStatements(watchdog, ifBB.getCondition(), statements, jumps); - statements.add(LoopStatementMaker.makeLoop(localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateStatements), jumps)); + statements.add(LoopStatementMaker.makeLoop( + localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateStatements), jumps)); makeStatements(watchdog, basicBlock.getNext(), statements, jumps); return; } @@ -861,7 +865,62 @@ protected Expression parseTernaryOperator(int lineNumber, Expression condition, } } - return new TernaryOperatorExpression(lineNumber, condition, exp1, exp2); + return newTernaryOperatorExpression(lineNumber, condition, exp1, exp2); + } + + protected TernaryOperatorExpression newTernaryOperatorExpression(int lineNumber, Expression condition, Expression expressionTrue, Expression expressionFalse) { + Type expressionTrueType = expressionTrue.getType(); + Type expressionFalseType = expressionFalse.getType(); + Type type; + + if (expressionTrue.getClass() == NullExpression.class) { + type = expressionFalseType; + } else if (expressionFalse.getClass() == NullExpression.class) { + type = expressionTrueType; + } else if (expressionTrueType.equals(expressionFalseType)) { + type = expressionTrueType; + } else if (expressionTrueType.isPrimitive() && expressionFalseType.isPrimitive()) { + int flags = ((PrimitiveType)expressionTrueType).getFlags() | ((PrimitiveType)expressionFalseType).getFlags(); + + if ((flags & FLAG_DOUBLE) != 0) { + type = TYPE_DOUBLE; + } else if ((flags & FLAG_FLOAT) != 0) { + type = TYPE_FLOAT; + } else if ((flags & FLAG_LONG) != 0) { + type = TYPE_LONG; + } else { + type = TYPE_INT; + } + } else if (expressionTrueType.isObject() && expressionFalseType.isObject()) { + ObjectType ot1 = (ObjectType)expressionTrueType; + ObjectType ot2 = (ObjectType)expressionFalseType; + + if (typeMaker.isAssignable(ot1, ot2)) { + type = getTernaryOperatorExpressionType(ot1, ot2); + } else if (typeMaker.isAssignable(ot2, ot1)) { + type = getTernaryOperatorExpressionType(ot2, ot1); + } else { + type = TYPE_OBJECT; + } + } else { + type = TYPE_OBJECT; + } + + return new TernaryOperatorExpression(lineNumber, type, condition, expressionTrue, expressionFalse); + } + + protected Type getTernaryOperatorExpressionType(ObjectType ot1, ObjectType ot2) { + if (ot1.getTypeArguments() == null) { + return ot1; + } else if (ot2.getTypeArguments() == null) { + return ot1.createType(null); + } else if (ot1.isTypeArgumentAssignableFrom(ot2)) { + return ot1; + } else if (ot2.isTypeArgumentAssignableFrom(ot1)) { + return ot1.createType(ot2.getTypeArguments()); + } else { + return ot1.createType(null); + } } protected boolean checkFieldReference(String fieldName, Expression expression) { @@ -903,7 +962,7 @@ protected Expression createObjectTypeReferenceDotClassExpression(int lineNumber, return new TypeReferenceDotClassExpression(lineNumber, ot); } - protected void parseByteCode(BasicBlock basicBlock, Statements statements) { + protected void parseByteCode(BasicBlock basicBlock, Statements statements) { byteCodeParser.parse(basicBlock, statements, stack); } @@ -934,10 +993,10 @@ protected void replacePreOperatorWithPostOperator(Statements statements) { protected void updateJumpStatements(Statements jumps) { assert false : "StatementMaker.updateJumpStatements(stmt) : 'jumps' list is not empty"; - Iterator iterator = jumps.iterator(); + Iterator iterator = jumps.iterator(); while (iterator.hasNext()) { - ClassFileBreakContinueStatement statement = iterator.next(); + ClassFileBreakContinueStatement statement = (ClassFileBreakContinueStatement)iterator.next(); statement.setStatement(new CommentStatement("// Byte code: goto -> " + statement.getTargetOffset())); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java index f895091b..b272dda9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java @@ -13,6 +13,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileNewExpression; import org.jd.core.v1.util.DefaultList; +import java.util.Iterator; import java.util.StringTokenizer; public class StringConcatenationUtil { @@ -59,7 +60,7 @@ public static Expression create(Expression expression, int lineNumber, String ty } } - return new ClassFileMethodInvocationExpression(lineNumber, null, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;", null, null); + return new ClassFileMethodInvocationExpression(null, lineNumber, null, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;", null, null); } public static Expression create(String recipe, BaseExpression parameters) { @@ -93,25 +94,20 @@ public static Expression create(String recipe, BaseExpression parameters) { } public static Expression create(BaseExpression parameters) { - if (parameters.isList()) { - DefaultList list = parameters.getList(); - - switch (list.size()) { - case 0: - return StringConstantExpression.EMPTY_STRING; - case 1: - return createFirstStringConcatenationItem(parameters.getFirst()); - default: - Expression expression = createFirstStringConcatenationItem(parameters.getFirst()); - - for (int i = 1, len = list.size(); i < len; i++) { - expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", list.get(i), 6); - } + switch (parameters.size()) { + case 0: + return StringConstantExpression.EMPTY_STRING; + case 1: + return createFirstStringConcatenationItem(parameters.getFirst()); + default: + Iterator iterator = parameters.iterator(); + Expression expression = createFirstStringConcatenationItem(iterator.next()); + + while (iterator.hasNext()) { + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", iterator.next(), 6); + } - return expression; - } - } else { - return createFirstStringConcatenationItem(parameters.getFirst()); + return expression; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java index b783e897..ec26bd33 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java @@ -26,7 +26,7 @@ public class SwitchStatementMaker { protected static final Integer MINUS_ONE = Integer.valueOf(-1); @SuppressWarnings("unchecked") - public static void makeSwitchString(LocalVariableMaker localVariableMaker, Statements statements, SwitchStatement switchStatement) { + public static void makeSwitchString(LocalVariableMaker localVariableMaker, Statements statements, SwitchStatement switchStatement) { int size = statements.size(); SwitchStatement previousSwitchStatement = (SwitchStatement)statements.get(size - 2); @@ -79,7 +79,7 @@ public static void makeSwitchString(LocalVariableMaker localVariableMaker, State assert (stmts != null) && (stmts.getClass() == Statements.class) && !((Statements) stmts).isEmpty(); - for (Statement stmt : (Statements) stmts) { + for (Statement stmt : stmts) { if (stmt.getClass() != IfStatement.class) { break; } @@ -192,7 +192,7 @@ public static void makeSwitchEnum(ClassFileBodyDeclaration bodyDeclaration, Swit if (syntheticClass != null) { // Javac switch-enum pattern bodyDeclaration = (ClassFileBodyDeclaration) syntheticClass.getBodyDeclaration(); - DefaultList statements = (DefaultList) bodyDeclaration.getMethodDeclarations().get(0).getStatements(); + DefaultList statements = bodyDeclaration.getMethodDeclarations().get(0).getStatements().getList(); updateSwitchStatement(switchStatement, statements.listIterator(1)); } } @@ -204,7 +204,7 @@ public static void makeSwitchEnum(ClassFileBodyDeclaration bodyDeclaration, Swit // Eclipse compiler switch-enum pattern for (ClassFileConstructorOrMethodDeclaration declaration : bodyDeclaration.getMethodDeclarations()) { if (declaration.getMethod().getName().equals(methodName)) { - DefaultList statements = (DefaultList)declaration.getStatements(); + DefaultList statements = declaration.getStatements().getList(); updateSwitchStatement(switchStatement, statements.listIterator(3)); break; } @@ -230,7 +230,7 @@ protected static void updateSwitchStatement(SwitchStatement switchStatement, Lis break; } - statement = statements.getList().getFirst(); + statement = statements.getFirst(); if (statement.getClass() != ExpressionStatement.class) { break; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java index d4ad0a0d..fef43908 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SynchronizedStatementMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -24,7 +24,7 @@ public class SynchronizedStatementMaker { - public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements) { + public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements) { // Remove monitor enter ClassFileMonitorEnterStatement monitorEnterStatement = (ClassFileMonitorEnterStatement) statements.removeLast(); Expression monitor = monitorEnterStatement.getMonitor(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java index cebadbeb..9d5be7d9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java @@ -23,7 +23,7 @@ public class TryWithResourcesStatementMaker { - public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, DefaultList catchClauses, Statements finallyStatements) { + public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, DefaultList catchClauses, Statements finallyStatements) { int size = statements.size(); if ((size < 2) || (finallyStatements == null) || (finallyStatements.size() != 1) || !checkThrowable(catchClauses)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index 76a62cad..4b3b8d37 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -14,6 +14,7 @@ import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.model.classfile.attribute.*; import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.BindTypeParametersToTypeArgumentsVisitor; import org.jd.core.v1.service.deserializer.classfile.ClassFileFormatException; import org.jd.core.v1.service.deserializer.classfile.ClassFileReader; @@ -21,6 +22,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.Iterator; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; @@ -50,9 +52,9 @@ public class TypeMaker { private HashMap internalTypeNameFieldNameToType = new HashMap<>(1024); private HashMap descriptorToObjectType = new HashMap<>(1024); private HashMap internalTypeNameToObjectType = new HashMap<>(1024); + private HashMap internalTypeNameToTypeTypes = new HashMap<>(1024); private HashMap internalTypeNameMethodNameDescriptorToMethodTypes = new HashMap<>(1024); private HashMap signatureToMethodTypes = new HashMap<>(1024); - private HashMap internalTypeNameToTypeParameters = new HashMap<>(1024); private HashMap hierarchy = new HashMap<>(1024); private ClassPathLoader classPathLoader = new ClassPathLoader(); @@ -108,7 +110,6 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { AttributeSignature attributeSignature = classFile.getAttribute("Signature"); if (attributeSignature == null) { - // Create 'typeSignature' with classFile start String superTypeName = classFile.getSuperTypeName(); String[] interfaceTypeNames = classFile.getInterfaceTypeNames(); @@ -131,15 +132,15 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { } } else { // Parse 'signature' attribute - SignatureReader reader = new SignatureReader(attributeSignature.getSignature()); + SignatureReader signatureReader = new SignatureReader(attributeSignature.getSignature()); - typeTypes.typeParameters = parseTypeParameters(reader); - typeTypes.superType = parseClassTypeSignature(reader, 0); + typeTypes.typeParameters = parseTypeParameters(signatureReader); + typeTypes.superType = parseClassTypeSignature(signatureReader, 0); - Type firstInterface = parseClassTypeSignature(reader, 0); + Type firstInterface = parseClassTypeSignature(signatureReader, 0); if (firstInterface != null) { - Type nextInterface = parseClassTypeSignature(reader, 0); + Type nextInterface = parseClassTypeSignature(signatureReader, 0); if (nextInterface == null) { typeTypes.interfaces = firstInterface; @@ -150,7 +151,7 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { do { list.add(nextInterface); - nextInterface = parseClassTypeSignature(reader, 0); + nextInterface = parseClassTypeSignature(signatureReader, 0); } while (nextInterface != null); typeTypes.interfaces = list; @@ -158,20 +159,17 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { } } - return typeTypes; - } + internalTypeNameToTypeTypes.put(internalTypeName, typeTypes); - public MethodTypes parseConstructorSignature(ClassFile classFile, Method method) { - String key = classFile.getInternalTypeName() + ":" + method.getDescriptor(); - return parseConstructorOrMethodSignature(method, key); + return typeTypes; } public MethodTypes parseMethodSignature(ClassFile classFile, Method method) { String key = classFile.getInternalTypeName() + ':' + method.getName() + method.getDescriptor(); - return parseConstructorOrMethodSignature(method, key); + return parseMethodSignature(method, key); } - private MethodTypes parseConstructorOrMethodSignature(Method method, String key) { + private MethodTypes parseMethodSignature(Method method, String key) { AttributeSignature attributeSignature = method.getAttribute("Signature"); String[] exceptionTypeNames = getExceptionTypeNames(method); MethodTypes methodTypes; @@ -254,7 +252,7 @@ private MethodTypes parseMethodSignature(String descriptor, String signature, St } else if (mtDescriptor.parameterTypes.size() == mtSignature.parameterTypes.size()) { return mtSignature; } else { - Types parameterTypes = new Types<>(mtDescriptor.parameterTypes.getList()); + Types parameterTypes = new Types(mtDescriptor.parameterTypes.getList()); parameterTypes.subList(parameterTypes.size() - mtSignature.parameterTypes.size(), parameterTypes.size()).clear(); parameterTypes.addAll(mtSignature.parameterTypes.getList()); @@ -432,7 +430,7 @@ private TypeParameter parseTypeParameter(SignatureReader reader) { // Parser bounds Type firstBound = null; - TypeBounds types = null; + Types types = null; while (reader.nextEqualsTo(':')) { // Skip ':' @@ -444,7 +442,7 @@ private TypeParameter parseTypeParameter(SignatureReader reader) { if (firstBound == null) { firstBound = bound; } else if (types == null) { - types = new TypeBounds(); + types = new Types(); types.add(firstBound); types.add(bound); } else { @@ -568,7 +566,7 @@ private BaseTypeArgument parseTypeArguments(SignatureReader reader) { if (nextTypeArgument == null) { return firstTypeArgument; } else { - ArrayTypeArguments typeArguments = new ArrayTypeArguments(); + TypeArguments typeArguments = new TypeArguments(); typeArguments.add(firstTypeArgument); do { @@ -866,6 +864,8 @@ public boolean isAssignable(ObjectType parent, ObjectType child) { return true; } else if (parent.getDimension() > 0) { return (parent.getDimension() == child.getDimension()) && parent.getInternalName().equals(child.getInternalName()); + } else if (child.getDimension() > 0) { + return false; } else { String parentInternalName = parent.getInternalName(); String childInternalName = child.getInternalName(); @@ -905,29 +905,27 @@ private boolean recursiveIsAssignable(String parentInternalName, String childInt return false; } - public BaseTypeParameter makeTypeParameters(ObjectType objectType) { - String internalTypeName = objectType.getInternalName(); - - if (internalTypeNameToTypeParameters.containsKey(internalTypeName)) { - return internalTypeNameToTypeParameters.get(internalTypeName); + public TypeTypes makeTypeTypes(String internalTypeName) { + if (internalTypeNameToTypeTypes.containsKey(internalTypeName)) { + return internalTypeNameToTypeTypes.get(internalTypeName); } - BaseTypeParameter typeParameters = null; + TypeTypes typeTypes = null; try { if (loader.canLoad(internalTypeName)) { - internalTypeNameToTypeParameters.put(internalTypeName, typeParameters = loadTypeParameters(internalTypeName, loader.load(internalTypeName))); + internalTypeNameToTypeTypes.put(internalTypeName, typeTypes = makeTypeTypes(internalTypeName, loader.load(internalTypeName))); } else if (classPathLoader.canLoad(internalTypeName)) { - internalTypeNameToTypeParameters.put(internalTypeName, typeParameters = loadTypeParameters(internalTypeName, classPathLoader.load(internalTypeName))); + internalTypeNameToTypeTypes.put(internalTypeName, typeTypes = makeTypeTypes(internalTypeName, classPathLoader.load(internalTypeName))); } } catch (Exception e) { assert ExceptionUtil.printStackTrace(e); } - return typeParameters; + return typeTypes; } - private BaseTypeParameter loadTypeParameters(String internalTypeName, byte[] data) throws Exception { + private TypeTypes makeTypeTypes(String internalTypeName, byte[] data) throws Exception { if (data == null) { return null; } @@ -941,9 +939,6 @@ private BaseTypeParameter loadTypeParameters(String internalTypeName, byte[] dat // Skip methods skipMembers(reader); - String outerTypeName = null; - ObjectType outerObjectType = null; - // Load attributes String signature = null; int count = reader.readUnsignedShort(); @@ -960,16 +955,77 @@ private BaseTypeParameter loadTypeParameters(String internalTypeName, byte[] dat } } + String[] superClassAndInterfaceNames = hierarchy.get(internalTypeName); + TypeTypes typeTypes = new TypeTypes(); + + typeTypes.thisType = makeFromInternalTypeName(internalTypeName); + if (signature == null) { - return null; + String superTypeName = superClassAndInterfaceNames[0]; + + typeTypes.superType = (superTypeName == null) ? null : makeFromInternalTypeName(superTypeName); + + switch (superClassAndInterfaceNames.length) { + case 0: + case 1: + break; + case 2: + typeTypes.interfaces = makeFromInternalTypeName(superClassAndInterfaceNames[1]); + break; + default: + int length = superClassAndInterfaceNames.length; + Types list = new Types(length-1); + for (int i=1; i bindings = new HashMap<>(); + + if (typeTypes.typeParameters.isList()) { + Iterator iteratorTypeParameter = typeTypes.typeParameters.iterator(); + Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); + + while (iteratorTypeParameter.hasNext()) { + bindings.put(iteratorTypeParameter.next().getIdentifier(), iteratorTypeArgument.next()); + } + } else { + bindings.put(typeTypes.typeParameters.getFirst().getIdentifier(), typeArguments.getTypeArgumentFirst()); + } + + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + + bindTypeParametersToTypeArgumentsVisitor.init(); + type.accept(bindTypeParametersToTypeArgumentsVisitor); + type = (Type) bindTypeParametersToTypeArgumentsVisitor.getType(); } } @@ -992,8 +1103,18 @@ public MethodTypes makeMethodTypes(String descriptor) { return parseMethodSignature(descriptor, null); } - public MethodTypes makeMethodTypes(ObjectType objectType, String methodName, String descriptor) { - String internalTypeName = objectType.getInternalName(); + public MethodTypes makeMethodTypes(String internalTypeName, String methodName, String descriptor) { + MethodTypes methodTypes = loadMethodTypes(internalTypeName, methodName, descriptor); + + if (methodTypes == null) { + String key = internalTypeName + ':' + methodName + descriptor; + internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes = parseMethodSignature(descriptor, null)); + } + + return methodTypes; + } + + private MethodTypes loadMethodTypes(String internalTypeName, String methodName, String descriptor) { String key = internalTypeName + ':' + methodName + descriptor; MethodTypes methodTypes = internalTypeNameMethodNameDescriptorToMethodTypes.get(key); @@ -1001,11 +1122,80 @@ public MethodTypes makeMethodTypes(ObjectType objectType, String methodName, Str // Load method if (loadFieldsAndMethods(internalTypeName)) { methodTypes = internalTypeNameMethodNameDescriptorToMethodTypes.get(key); + if (methodTypes == null) { - internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes = parseMethodSignature(descriptor, null)); + TypeTypes typeTypes = makeTypeTypes(internalTypeName); + + if (typeTypes != null) { + if (typeTypes.superType != null) { + methodTypes = loadMethodTypes(typeTypes.superType, methodName, descriptor); + } + + if ((methodTypes == null) && (typeTypes.interfaces != null)) { + if (typeTypes.interfaces.isList()) { + for (Type interfaze : typeTypes.interfaces) { + methodTypes = loadMethodTypes((ObjectType) interfaze, methodName, descriptor); + if (methodTypes != null) + break; + } + } else { + methodTypes = loadMethodTypes((ObjectType) typeTypes.interfaces.getFirst(), methodName, descriptor); + } + } + } } - } else { - internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes = parseMethodSignature(descriptor, null)); + + if (methodTypes != null) { + internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes); + } + } + } + + return methodTypes; + } + + private MethodTypes loadMethodTypes(ObjectType objectType, String methodName, String descriptor) { + String internalTypeName = objectType.getInternalName(); + BaseTypeArgument typeArguments = objectType.getTypeArguments(); + MethodTypes methodTypes = loadMethodTypes(internalTypeName, methodName, descriptor); + + if ((methodTypes != null) && (typeArguments != null)) { + TypeTypes typeTypes = makeTypeTypes(internalTypeName); + + if ((typeTypes != null) && (typeTypes.typeParameters != null)) { + BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); + HashMap bindings = new HashMap<>(); + MethodTypes newMethodTypes = new MethodTypes(); + + if (typeTypes.typeParameters.isList()) { + Iterator iteratorTypeParameter = typeTypes.typeParameters.iterator(); + Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); + + while (iteratorTypeParameter.hasNext()) { + bindings.put(iteratorTypeParameter.next().getIdentifier(), iteratorTypeArgument.next()); + } + } else { + bindings.put(typeTypes.typeParameters.getFirst().getIdentifier(), typeArguments.getTypeArgumentFirst()); + } + + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + + if (methodTypes.parameterTypes == null) { + newMethodTypes.parameterTypes = null; + } else { + bindTypeParametersToTypeArgumentsVisitor.init(); + methodTypes.parameterTypes.accept(bindTypeParametersToTypeArgumentsVisitor); + newMethodTypes.parameterTypes = bindTypeParametersToTypeArgumentsVisitor.getType(); + } + + bindTypeParametersToTypeArgumentsVisitor.init(); + methodTypes.returnedType.accept(bindTypeParametersToTypeArgumentsVisitor); + newMethodTypes.returnedType = (Type)bindTypeParametersToTypeArgumentsVisitor.getType(); + + newMethodTypes.typeParameters = null; + newMethodTypes.exceptions = methodTypes.exceptions; + + methodTypes = newMethodTypes; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java new file mode 100644 index 00000000..e28e2dd3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.util; + +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.BindTypeParametersToTypeArgumentsVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.PopulateBindingsWithTypeArgumentVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.PopulateBindingsWithTypeParameterVisitor; +import org.jd.core.v1.util.DefaultList; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_STATIC; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; + +public class TypeParametersToTypeArgumentsBinder { + protected PopulateBindingsWithTypeParameterVisitor populateBindingsWithTypeParameterVisitor = new PopulateBindingsWithTypeParameterVisitor(); + protected BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); + + protected TypeMaker typeMaker; + protected String internalTypeName; + protected PopulateBindingsWithTypeArgumentVisitor populateBindingsWithTypeArgumentVisitor; + protected Map contextualBindings; + + public TypeParametersToTypeArgumentsBinder( + TypeMaker typeMaker, String internalTypeName, ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { + this.typeMaker = typeMaker; + this.internalTypeName = internalTypeName; + this.populateBindingsWithTypeArgumentVisitor = new PopulateBindingsWithTypeArgumentVisitor(typeMaker); + + if ((comd.getFlags() & FLAG_STATIC) == 0) { + this.contextualBindings = bodyDeclaration.getBindings(); + } else { + this.contextualBindings = Collections.emptyMap(); + } + + if (comd.getTypeParameters() != null) { + HashMap bindings = new HashMap<>(); + + bindings.putAll(this.contextualBindings); + + populateBindingsWithTypeParameterVisitor.init(bindings); + comd.getTypeParameters().accept(populateBindingsWithTypeParameterVisitor); + + for (HashMap.Entry entry : bindings.entrySet()) { + if (entry.getValue() == null) { + entry.setValue(new GenericType(entry.getKey())); + } + } + + this.contextualBindings = bindings; + } + } + + public ClassFileConstructorInvocationExpression newConstructorInvocationExpression( + int lineNumber, ObjectType objectType, String descriptor, + TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { + + BaseType parameterTypes = methodTypes.parameterTypes; + Map bindings = contextualBindings; + + if ((parameterTypes != null) && (methodTypes.typeParameters != null)) { + bindings = new HashMap<>(); + bindings.putAll(contextualBindings); + + populateBindingsWithTypeParameterVisitor.init(bindings); + methodTypes.typeParameters.accept(populateBindingsWithTypeParameterVisitor); + + if (parameterTypes.size() > 1) { + Iterator parametersIterator = parameters.iterator(); + Iterator parameterTypesIterator = parameterTypes.iterator(); + + while (parametersIterator.hasNext()) { + Expression parameter = parametersIterator.next(); + Type parameterType = parameterTypesIterator.next(); + + if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { + populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); + parameterType.accept(populateBindingsWithTypeArgumentVisitor); + } + } + } else if (parameterTypes.size() > 0) { + Expression parameter = parameters.getFirst(); + + if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { + populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); + parameterTypes.getFirst().accept(populateBindingsWithTypeArgumentVisitor); + } + } + } + + if (!bindings.isEmpty() && !bindings.containsValue(null)) { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + parameterTypes = bindParameterTypesWithArgumentTypes(TYPE_OBJECT, parameterTypes); + } + + parameters = prepareParameters(parameters, parameterTypes); + return new ClassFileConstructorInvocationExpression(lineNumber, objectType, descriptor, parameterTypes, parameters); + } + + public ClassFileSuperConstructorInvocationExpression newSuperConstructorInvocationExpression( + int lineNumber, ObjectType objectType, String descriptor, + TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { + + BaseType parameterTypes = methodTypes.parameterTypes; + Map bindings = contextualBindings; + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(internalTypeName); + + if ((typeTypes != null) && (typeTypes.superType != null) && (typeTypes.superType.getTypeArguments() != null)) { + TypeMaker.TypeTypes superTypeTypes = typeMaker.makeTypeTypes(objectType.getInternalName()); + + if (superTypeTypes != null) { + bindings = createBindings(superTypeTypes.typeParameters, typeTypes.superType.getTypeArguments(), methodTypes.typeParameters); + } + } + + if (!bindings.isEmpty()) { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + parameterTypes = bindParameterTypesWithArgumentTypes(objectType, methodTypes.parameterTypes); + } + + parameters = prepareParameters(parameters, parameterTypes); + return new ClassFileSuperConstructorInvocationExpression(lineNumber, objectType, descriptor, parameterTypes, parameters); + } + + public ClassFileMethodInvocationExpression newMethodInvocationExpression( + int lineNumber, Expression expression, ObjectType objectType, String name, String descriptor, + TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { + + Type returnedType = methodTypes.returnedType; + BaseType parameterTypes = methodTypes.parameterTypes; + + if (methodTypes.typeParameters == null) { + Map bindings = contextualBindings; + + if (expression.getClass() != ThisExpression.class) { + Type expressionType = expression.getType(); + + if (expressionType.isObject()) { + ObjectType expressionObjectType = (ObjectType) expressionType; + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(objectType.getInternalName()); + + if (typeTypes != null) { + BaseTypeParameter typeParameters = typeTypes.typeParameters; + BaseTypeArgument typeArguments; + + if (expression.getClass() == SuperExpression.class) { + typeTypes = typeMaker.makeTypeTypes(internalTypeName); + typeArguments = typeTypes.superType.getTypeArguments(); + } else { + typeArguments = expressionObjectType.getTypeArguments(); + } + + if ((typeParameters != null) && (typeArguments == null)) { + Class expressionClass = expression.getClass(); + + if ((expressionClass == ObjectTypeReferenceExpression.class) && name.startsWith("access$")) { + // Bridge method => Do not bind + bindings = Collections.emptyMap(); + } else if ((expressionClass == ClassFileMethodInvocationExpression.class) && ((ClassFileMethodInvocationExpression)expression).getName().startsWith("access$")) { + // Bridge method => Do not bind + bindings = Collections.emptyMap(); + } else if ((expressionClass == FieldReferenceExpression.class) && ((FieldReferenceExpression)expression).getName().startsWith("this$")) { + // Bridge method => Do not bind + bindings = Collections.emptyMap(); + } else { + bindings = new HashMap<>(); + bindings.putAll(contextualBindings); + for (TypeParameter typeParameter : typeParameters) { + bindings.put(typeParameter.getIdentifier(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } + } + } else { + bindings = createBindings(typeParameters, typeArguments, methodTypes.typeParameters); + } + } + } + } + + if (!bindings.isEmpty()) { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + returnedType = (Type) bindParameterTypesWithArgumentTypes(objectType, methodTypes.returnedType); + parameterTypes = bindParameterTypesWithArgumentTypes(objectType, methodTypes.parameterTypes); + } + + parameters = prepareParameters(parameters, parameterTypes); + } + + return new ClassFileMethodInvocationExpression( + this, lineNumber, methodTypes.typeParameters, returnedType, expression, + objectType.getInternalName(), name, descriptor, parameterTypes, parameters); + } + + public FieldReferenceExpression newFieldReferenceExpression( + int lineNumber, Type type, Expression expression, ObjectType objectType, String name, String descriptor) { + + if (type.isObject()) { + ObjectType ot = (ObjectType)type; + + if (ot.getTypeArguments() != null) { + Map bindings = contextualBindings; + + if (expression.getClass() != ThisExpression.class) { + Type expressionType = expression.getType(); + + if (expressionType.isObject()) { + ObjectType expressionObjectType = (ObjectType) expressionType; + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(expressionObjectType.getInternalName()); + + if (typeTypes != null) { + BaseTypeParameter typeParameters = typeTypes.typeParameters; + BaseTypeArgument typeArguments = expressionObjectType.getTypeArguments(); + + if ((typeParameters != null) && (typeArguments == null)) { + bindings = new HashMap<>(); + bindings.putAll(contextualBindings); + for (TypeParameter typeParameter : typeParameters) { + bindings.put(typeParameter.getIdentifier(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } + } else { + bindings = createBindings(typeParameters, typeArguments, null); + } + } + } + } + + if (!bindings.isEmpty()) { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + type = (Type) bindParameterTypesWithArgumentTypes(objectType, type); + } + } + } + + return new FieldReferenceExpression(lineNumber, type, expression, objectType.getInternalName(), name, descriptor); + } + + public void updateNewExpression(Expression expression, String descriptor, TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { + ClassFileNewExpression ne = (ClassFileNewExpression)expression; + BaseType parameterTypes = methodTypes.parameterTypes; + Map bindings = contextualBindings; + + if (!ne.getObjectType().getInternalName().equals(internalTypeName)) { + if (parameterTypes != null) { + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(ne.getObjectType().getInternalName()); + + if ((typeTypes != null) && (typeTypes.typeParameters != null)) { + bindings = new HashMap<>(); + bindings.putAll(contextualBindings); + + populateBindingsWithTypeParameterVisitor.init(bindings); + typeTypes.typeParameters.accept(populateBindingsWithTypeParameterVisitor); + + if (parameterTypes.size() > 1) { + Iterator parametersIterator = parameters.iterator(); + Iterator parameterTypesIterator = parameterTypes.iterator(); + + while (parametersIterator.hasNext()) { + Expression parameter = parametersIterator.next(); + Type parameterType = parameterTypesIterator.next(); + + if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { + populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); + parameterType.accept(populateBindingsWithTypeArgumentVisitor); + } + } + } else if (parameterTypes.size() > 0) { + Expression parameter = parameters.getFirst(); + + if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { + populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); + parameterTypes.getFirst().accept(populateBindingsWithTypeArgumentVisitor); + } + } + + if (!bindings.containsValue(null)) { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + + if (typeTypes.typeParameters.isList()) { + TypeArguments tas = new TypeArguments(typeTypes.typeParameters.size()); + boolean object = true; + + for (TypeParameter typeParameter : typeTypes.typeParameters) { + bindTypeParametersToTypeArgumentsVisitor.init(); + new GenericType(typeParameter.getIdentifier()).accept(bindTypeParametersToTypeArgumentsVisitor); + BaseType baseType = bindTypeParametersToTypeArgumentsVisitor.getType(); + object &= TYPE_OBJECT.equals(baseType); + tas.add((Type) baseType); + } + + if (!object) { + ne.setType(ne.getObjectType().createType(tas)); + } + } else { + bindTypeParametersToTypeArgumentsVisitor.init(); + new GenericType(typeTypes.typeParameters.getFirst().getIdentifier()).accept(bindTypeParametersToTypeArgumentsVisitor); + BaseType baseType = bindTypeParametersToTypeArgumentsVisitor.getType(); + + if (!TYPE_OBJECT.equals(baseType)) { + ne.setType(ne.getObjectType().createType((Type)baseType)); + } + } + } + } + } + + if (!bindings.isEmpty() && !bindings.containsValue(null)) { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + parameterTypes = bindParameterTypesWithArgumentTypes(ne.getObjectType(), parameterTypes); + } + } + + parameters = prepareParameters(parameters, parameterTypes); + ((ClassFileNewExpression)expression).set(descriptor, parameterTypes, parameters); + } + + protected Map createBindings(BaseTypeParameter typeParameters, BaseTypeArgument typeArguments, BaseTypeParameter methodTypeParameters) { + if ((typeParameters == null) && (methodTypeParameters == null)) { + return contextualBindings; + } else { + HashMap bindings = new HashMap<>(); + + bindings.putAll(contextualBindings); + + if ((typeParameters != null) && (typeArguments != null)) { + if (typeParameters.isList()) { + Iterator iteratorTypeParameter = typeParameters.iterator(); + Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); + + while (iteratorTypeParameter.hasNext()) { + bindings.put(iteratorTypeParameter.next().getIdentifier(), iteratorTypeArgument.next()); + } + } else { + bindings.put(typeParameters.getFirst().getIdentifier(), typeArguments.getTypeArgumentFirst()); + } + } + + if (methodTypeParameters != null) { + if (methodTypeParameters.isList()) { + for (TypeParameter tp : methodTypeParameters) { + String identifier = tp.getIdentifier(); + bindings.put(identifier, new GenericType(identifier)); + } + } else { + String identifier = methodTypeParameters.getFirst().getIdentifier(); + bindings.put(identifier, new GenericType(identifier)); + } + } + + return bindings; + } + } + + protected BaseType bindParameterTypesWithArgumentTypes(ObjectType objectType, BaseType baseType) { + if (baseType == null) { + return null; + } + + if (objectType.getInternalName().equals(internalTypeName)) { + return baseType; + } + + bindTypeParametersToTypeArgumentsVisitor.init(); + baseType.accept(bindTypeParametersToTypeArgumentsVisitor); + + return bindTypeParametersToTypeArgumentsVisitor.getType(); + } + + @SuppressWarnings("unchecked") + protected BaseExpression prepareParameters(BaseExpression parameterExpressions, BaseType parameterTypes) { + if (parameterTypes != null) { + int size = parameterTypes.size(); + + if (size == 1) { + Expression parameter = parameterExpressions.getFirst(); + Type type = parameterTypes.getFirst(); + + if (parameter.getClass() == ClassFileLocalVariableReferenceExpression.class) { + AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) parameter).getLocalVariable(); + localVariable.typeOnLeft(checkTypeArguments(type, localVariable)); + } + + bindParameterTypesWithArgumentTypes(type, parameter); + } else if (size > 1) { + DefaultList parameters = parameterExpressions.getList(); + DefaultList types = parameterTypes.getList(); + + for (int i=0; i bindings = new HashMap<>(); + + if (mie.getExpression().getClass() != ObjectTypeReferenceExpression.class) { + // Non-static method invocation + bindings.putAll(contextualBindings); + } + + if (mie.getTypeParameters() != null) { + populateBindingsWithTypeParameterVisitor.init(bindings); + mie.getTypeParameters().accept(populateBindingsWithTypeParameterVisitor); + } + + if (type != PrimitiveType.TYPE_VOID) { + populateBindingsWithTypeArgumentVisitor.init(bindings, type); + mie.getType().accept(populateBindingsWithTypeArgumentVisitor); + } + + if (mie.getParameterTypes() != null) { + BaseType parameterTypes = mie.getParameterTypes(); + + if (parameterTypes.size() > 1) { + Iterator parametersIterator = mie.getParameters().iterator(); + Iterator parameterTypesIterator = mie.getParameterTypes().iterator(); + + while (parametersIterator.hasNext()) { + Expression parameter = parametersIterator.next(); + Type parameterType = parameterTypesIterator.next(); + + if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression)parameter).getTypeParameters() == null)) { + populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); + parameterType.accept(populateBindingsWithTypeArgumentVisitor); + } + } + } else if (parameterTypes.size() > 0) { + Expression parameter = mie.getParameters().getFirst(); + + if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression)parameter).getTypeParameters() == null)) { + populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); + parameterTypes.getFirst().accept(populateBindingsWithTypeArgumentVisitor); + } + } + } + + assert !bindings.isEmpty() : "TypeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(...): Bindings is empty"; + + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + + bindTypeParametersToTypeArgumentsVisitor.init(); + mie.getType().accept(bindTypeParametersToTypeArgumentsVisitor); + mie.setType((Type) bindTypeParametersToTypeArgumentsVisitor.getType()); + + if (mie.getParameterTypes() != null) { + bindTypeParametersToTypeArgumentsVisitor.init(); + mie.getParameterTypes().accept(bindTypeParametersToTypeArgumentsVisitor); + mie.setParameterTypes(bindTypeParametersToTypeArgumentsVisitor.getType()); + + BaseType parameterTypes = mie.getParameterTypes(); + + if (parameterTypes.size() > 1) { + Iterator parametersIterator = mie.getParameters().iterator(); + Iterator parameterTypesIterator = mie.getParameterTypes().iterator(); + + while (parametersIterator.hasNext()) { + bindParameterTypesWithArgumentTypes(parameterTypesIterator.next(), parametersIterator.next()); + } + } else if (parameterTypes.size() > 0) { + bindParameterTypesWithArgumentTypes(parameterTypes.getFirst(), mie.getParameters().getFirst()); + } + } + + bindParameterTypesWithArgumentTypes(mie.getType(), mie.getExpression()); + } + + public static void staticBindParameterTypesWithArgumentTypes(Type type, Expression expression) { + if (expression.getClass() == ClassFileMethodInvocationExpression.class) { + ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; + TypeParametersToTypeArgumentsBinder binder = mie.getBinder(); + + if (binder != null) { + binder.bindParameterTypesWithArgumentTypes(type, mie); + } + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java index 5ac28971..b68c695a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -13,7 +13,8 @@ import org.jd.core.v1.model.javasyntax.reference.*; import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.*; -import org.jd.core.v1.util.DefaultList; + +import java.util.ListIterator; public abstract class AbstractUpdateExpressionVisitor extends AbstractJavaSyntaxVisitor { protected abstract Expression updateExpression(Expression expression); @@ -24,10 +25,12 @@ protected BaseExpression updateBaseExpression(BaseExpression baseExpression) { } if (baseExpression.isList()) { - DefaultList list = baseExpression.getList(); - for (int length=list.size(), i=0; i iterator = baseExpression.getList().listIterator(); + + while (iterator.hasNext()) { + iterator.set(updateExpression(iterator.next())); } + return baseExpression; } @@ -383,12 +386,11 @@ public void visit(WhileStatement statement) { @Override public void visit(SwitchStatement.DefaultLabel statement) {} @Override public void visit(InnerObjectReference reference) {} - @Override public void visit(ArrayTypeArguments type) {} + @Override public void visit(TypeArguments type) {} @Override public void visit(WildcardExtendsTypeArgument type) {} @Override public void visit(ObjectType type) {} @Override public void visit(InnerObjectType type) {} @Override public void visit(WildcardSuperTypeArgument type) {} @Override public void visit(Types list) {} - @Override public void visit(TypeBounds list) {} @Override public void visit(TypeParameterWithTypeBounds type) {} } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index 3ec3bdcc..e67b3a4e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -125,6 +125,11 @@ public void visit(ExpressionVariableInitializer declaration) { } } + if (expression.getClass() == NewInitializedArray.class) { + ((NewInitializedArray)expression).getArrayInitializer().accept(this); + return; + } + Type t = type; if (extraDimension > 0) { @@ -159,12 +164,8 @@ public void visit(MethodInvocationExpression expression) { if (parameters != null) { ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; - if (mie.getTypeParameters() == null) { - // Do not add cast expression if method contains type parameters - expression.setParameters(updateExpressions(mie.getParameterTypes(), parameters)); - } else { - parameters.accept(this); - } + parameters.accept(this); + expression.setParameters(updateExpressions(mie.getParameterTypes(), parameters)); } expression.getExpression().accept(this); @@ -236,9 +237,7 @@ protected BaseExpression updateExpressions(BaseType types, BaseExpression expres } private Expression updateExpression(Type type, Expression expression) { - Class expressionClass = expression.getClass(); - - if (expressionClass != NullExpression.class) { + if (match(expression)) { Type expressionType = expression.getType(); if (!expressionType.equals(type) && !TYPE_OBJECT.equals(type)) { @@ -249,17 +248,21 @@ private Expression updateExpression(Type type, Expression expression) { String internalName = objectType.getInternalName(); if (internalName.equals(expressionObjectType.getInternalName()) || typeMaker.isAssignable(objectType, expressionObjectType)) { - if (!internalName.equals(TYPE_CLASS.getInternalName())) { - if (expressionObjectType.getTypeArguments() != null) { - if ((objectType.getTypeArguments() == null) || !objectType.getTypeArguments().isTypeArgumentAssignableFrom(expressionObjectType.getTypeArguments())) { - expression = addCastExpression(type, expression); - } + if (expressionObjectType.getTypeArguments() == null) { + if (objectType.getTypeArguments() != null) { + expression = addCastExpression(type, expression); + } + } else { + if (objectType.getTypeArguments() == null) { + expression = addCastExpression(type, expression); + } else if (!objectType.getTypeArguments().isTypeArgumentAssignableFrom(expressionObjectType.getTypeArguments())) { + expression = addCastExpression(objectType.createType(null), expression); } } } } } else if (type.isGeneric()) { - if (expressionType.isObject()) { + if (expressionType.isObject() || expressionType.isGeneric()) { expression = addCastExpression(type, expression); } } @@ -271,10 +274,36 @@ private Expression updateExpression(Type type, Expression expression) { return expression; } + private static final boolean match(Expression expression) { + Class expressionClass = expression.getClass(); + + if (expressionClass == NullExpression.class) { + // Do not add a cast before a null value + return false; + } + + if (expressionClass == ClassFileMethodInvocationExpression.class) { + ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; + + if (mie.getTypeParameters() != null) { + // Do not add a cast before parameterized method invocation + return false; + } + } + + return true; + } + private static final Expression addCastExpression(Type type, Expression expression) { if (expression.getClass() == CastExpression.class) { - ((CastExpression)expression).setType(type); - return expression; + CastExpression ca = (CastExpression)expression; + + if (type.equals(ca.getExpression().getType())) { + return ca.getExpression(); + } else { + ca.setType(type); + return ca; + } } else { return new CastExpression(expression.getLineNumber(), type, expression); } @@ -297,12 +326,11 @@ private static final Expression addCastExpression(Type type, Expression expressi @Override public void visit(TypeReferenceDotClassExpression expression) {} @Override public void visit(ObjectReference reference) {} @Override public void visit(InnerObjectReference reference) {} - @Override public void visit(ArrayTypeArguments type) {} + @Override public void visit(TypeArguments type) {} @Override public void visit(WildcardExtendsTypeArgument type) {} @Override public void visit(ObjectType type) {} @Override public void visit(InnerObjectType type) {} @Override public void visit(WildcardSuperTypeArgument type) {} @Override public void visit(Types list) {} - @Override public void visit(TypeBounds list) {} @Override public void visit(TypeParameterWithTypeBounds type) {} } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java new file mode 100644 index 00000000..c03705b8 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import java.util.Map; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; + +public class BindTypeParametersToTypeArgumentsVisitor extends AbstractNopTypeVisitor { + protected BindTypeArgumentVisitor bindTypeArgumentVisitor = new BindTypeArgumentVisitor(); + protected TypeArgumentToTypeVisitor typeArgumentToTypeVisitor = new TypeArgumentToTypeVisitor(); + + protected Map bindings; + protected BaseType result; + + public void setBindings(Map bindings) { + bindTypeArgumentVisitor.setBindings(this.bindings = bindings); + } + + public void init() { + this.result = null; + } + + public BaseType getType() { + return result; + } + + @Override + public void visit(PrimitiveType type) { + result = type; + } + + @Override + public void visit(ObjectType type) { + BaseTypeArgument typeArguments = type.getTypeArguments(); + + if (typeArguments == null) { + result = type; + } else { + bindTypeArgumentVisitor.init(); + typeArguments.accept(bindTypeArgumentVisitor); + BaseTypeArgument ta = bindTypeArgumentVisitor.getTypeArgument(); + + if (typeArguments == ta) { + result = type; + } else if (WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT == ta) { + result = type.createType(null); + } else { + result = type.createType(ta); + } + } + } + + @Override + public void visit(InnerObjectType type) { + type.getOuterType().accept(this); + + BaseTypeArgument typeArguments = type.getTypeArguments(); + + if (type.getOuterType() == result) { + if (typeArguments == null) { + result = type; + } else { + bindTypeArgumentVisitor.init(); + typeArguments.accept(bindTypeArgumentVisitor); + BaseTypeArgument ta = bindTypeArgumentVisitor.getTypeArgument(); + + if (typeArguments == ta) { + result = type; + } else if (WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT == ta) { + result = type.createType(null); + } else { + result = type.createType(ta); + } + } + } else { + ObjectType outerObjectType = (ObjectType) result; + + if (typeArguments != null) { + bindTypeArgumentVisitor.init(); + typeArguments.accept(bindTypeArgumentVisitor); + typeArguments = bindTypeArgumentVisitor.getTypeArgument(); + + if (WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT == typeArguments) { + typeArguments = null; + } + } + + result = new InnerObjectType(type.getInternalName(), type.getQualifiedName(), type.getName(), typeArguments, type.getDimension(), outerObjectType); + } + } + + @Override + public void visit(GenericType type) { + TypeArgument ta = bindings.get(type.getName()); + + if (ta == null) { + result = TYPE_OBJECT.createType(type.getDimension()); + } else if (ta == WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT) { + result = TYPE_OBJECT.createType(type.getDimension()); + } else { + typeArgumentToTypeVisitor.init(); + ta.accept(typeArgumentToTypeVisitor); + result = typeArgumentToTypeVisitor.getType().createType(type.getDimension()); + } + } + + @Override + public void visit(Types types) { + int size = types.size(); + int i; + + for (i=0; i bindings; + protected BaseTypeArgument result; + + public void setBindings(Map bindings) { + this.bindings = bindings; + } + + public void init() { + this.result = null; + } + + public BaseTypeArgument getTypeArgument() { + if ((result == null) || TYPE_OBJECT.equals(result)) { + return null; + } + + return result; + } + + @Override + public void visit(TypeArguments arguments) { + int size = arguments.size(); + int i; + + for (i=0; i synthetic method method.setFlags(method.getFlags() | FLAG_SYNTHETIC); method.accept(this); @@ -64,7 +64,7 @@ public void visit(BodyDeclaration declaration) { } } else { Type type = method.getParameterTypes().getFirst(); - if (type.isObject() && ((ObjectType) type).getName() == null) { + if (type.isObject() && (type.getName() == null)) { // Synthetic type in parameterTypes -> synthetic method method.setFlags(method.getFlags() | FLAG_SYNTHETIC); method.accept(this); @@ -87,34 +87,33 @@ public void visit(FieldDeclaration declaration) {} @Override public void visit(ConstructorDeclaration declaration) { - ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comdwln, true, comdwln.getParameterTypes()); + ClassFileConstructorOrMethodDeclaration comd = (ClassFileConstructorOrMethodDeclaration)declaration; + LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comd, true, comd.getParameterTypes()); - createParametersVariablesAndStatements(comdwln, localVariableMaker); + createParametersVariablesAndStatements(comd, localVariableMaker); } @Override public void visit(MethodDeclaration declaration) { - ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comdwln, false, comdwln.getParameterTypes()); + ClassFileConstructorOrMethodDeclaration comd = (ClassFileConstructorOrMethodDeclaration)declaration; + LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comd, false, comd.getParameterTypes()); - createParametersVariablesAndStatements(comdwln, localVariableMaker); + createParametersVariablesAndStatements(comd, localVariableMaker); } @Override public void visit(StaticInitializerDeclaration declaration) { - ClassFileConstructorOrMethodDeclaration comdwln = (ClassFileConstructorOrMethodDeclaration)declaration; - LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comdwln, false, null); + ClassFileConstructorOrMethodDeclaration comd = (ClassFileConstructorOrMethodDeclaration)declaration; + LocalVariableMaker localVariableMaker = new LocalVariableMaker(typeMaker, comd, false, null); - createParametersVariablesAndStatements(comdwln, localVariableMaker); + createParametersVariablesAndStatements(comd, localVariableMaker); } - protected void createParametersVariablesAndStatements(ClassFileConstructorOrMethodDeclaration comdwln, LocalVariableMaker localVariableMaker) { - ClassFile classFile = comdwln.getClassFile(); - ClassFileBodyDeclaration bodyDeclaration = comdwln.getBodyDeclaration(); - Method method = comdwln.getMethod(); - Type returnedType = comdwln.getReturnedType(); - StatementMaker statementMaker = new StatementMaker(typeMaker, localVariableMaker, classFile, bodyDeclaration, returnedType); + protected void createParametersVariablesAndStatements(ClassFileConstructorOrMethodDeclaration comd, LocalVariableMaker localVariableMaker) { + ClassFile classFile = comd.getClassFile(); + ClassFileBodyDeclaration bodyDeclaration = comd.getBodyDeclaration(); + Method method = comd.getMethod(); + StatementMaker statementMaker = new StatementMaker(typeMaker, localVariableMaker, classFile, bodyDeclaration, comd); try { ControlFlowGraph cfg = ControlFlowGraphMaker.make(method); @@ -124,22 +123,22 @@ protected void createParametersVariablesAndStatements(ClassFileConstructorOrMeth ControlFlowGraphLoopReducer.reduce(cfg); if (ControlFlowGraphReducer.reduce(cfg)) { - comdwln.setStatements(statementMaker.make(cfg)); + comd.setStatements(statementMaker.make(cfg)); } else { - comdwln.setStatements(new ByteCodeStatement(ByteCodeWriter.write("// ", method))); + comd.setStatements(new ByteCodeStatement(ByteCodeWriter.write("// ", method))); } } } catch (Exception e) { assert ExceptionUtil.printStackTrace(e); - comdwln.setStatements(new ByteCodeStatement(ByteCodeWriter.write("// ", method))); + comd.setStatements(new ByteCodeStatement(ByteCodeWriter.write("// ", method))); } if ((classFile.getAccessFlags() & FLAG_INTERFACE) != 0) { - comdwln.setFlags(comdwln.getFlags() & ~(FLAG_PUBLIC|FLAG_ABSTRACT)); + comd.setFlags(comd.getFlags() & ~(FLAG_PUBLIC|FLAG_ABSTRACT)); } localVariableMaker.make(); - comdwln.setFormalParameters(localVariableMaker.getFormalParameters()); + comd.setFormalParameters(localVariableMaker.getFormalParameters()); } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java index b5b570e4..d73ff764 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateLocalVariableVisitor.java @@ -11,7 +11,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; -public class CreateLocalVariableVisitor extends AbstractNopTypeVisitor implements LocalVariableVisitor { +public class CreateLocalVariableVisitor extends AbstractNopTypeArgumentVisitor implements LocalVariableVisitor { protected TypeMaker typeMaker; protected int index; protected int offset; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java index 4042dd9b..8b4ba0e6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateParameterVisitor.java @@ -14,7 +14,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.PrimitiveLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; -public class CreateParameterVisitor extends AbstractNopTypeVisitor { +public class CreateParameterVisitor extends AbstractNopTypeArgumentVisitor { protected TypeMaker typeMaker; protected int index; protected String name; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java index 923d2d51..a4e3806d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateTypeFromTypeArgumentVisitor.java @@ -9,11 +9,11 @@ import org.jd.core.v1.model.javasyntax.type.*; -public class CreateTypeFromTypeArgumentVisitor extends AbstractNopTypeVisitor { +public class CreateTypeFromTypeArgumentVisitor implements TypeArgumentVisitor { protected Type type; public CreateTypeFromTypeArgumentVisitor() { - init(); + type = null; } public void init() { @@ -24,6 +24,9 @@ public Type getType() { return type; } + @Override public void visit(TypeArguments arguments) { this.type = null; } + @Override public void visit(DiamondTypeArgument argument) { this.type = null; } + @Override public void visit(WildcardTypeArgument type) { this.type = null; } @Override public void visit(WildcardExtendsTypeArgument type) { this.type = type.getType(); } @Override public void visit(WildcardSuperTypeArgument type) { this.type = type.getType(); } @Override public void visit(PrimitiveType type) { this.type = type; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java index dd8f97a1..053c1b16 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GenerateParameterSuffixNameVisitor.java @@ -11,7 +11,7 @@ import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; -public class GenerateParameterSuffixNameVisitor extends AbstractNopTypeVisitor { +public class GenerateParameterSuffixNameVisitor extends AbstractNopTypeArgumentVisitor { protected String suffix; public String getSuffix() { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java index c55abc7a..494bd455 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java @@ -96,7 +96,7 @@ public void visit(FieldDeclarator declaration) { @Override @SuppressWarnings("unchecked") public void visit(NewExpression expression) { - Expressions parameters = (Expressions)expression.getParameters(); + Expressions parameters = (Expressions)expression.getParameters(); Expression exp = parameters.get(1); if (exp.getClass() == CastExpression.class) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 6ca0fb56..ab86b971 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -14,12 +14,16 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.BaseType; +import org.jd.core.v1.model.javasyntax.type.InnerObjectType; import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileNewExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.util.DefaultList; import java.util.*; @@ -28,8 +32,9 @@ public class InitInnerClassVisitor extends AbstractJavaSyntaxVisitor { protected UpdateFieldReferencesVisitor updateFieldReferencesVisitor = new UpdateFieldReferencesVisitor(); + protected DefaultList syntheticInnerFieldNames = new DefaultList<>(); + protected Map> syntheticInnerFieldNameToSyntheticInnerFieldReferences = new HashMap<>(); protected ObjectType outerType; - protected DefaultList outerLocalVariableNames = new DefaultList<>(); @Override public void visit(AnnotationDeclaration declaration) { @@ -57,16 +62,24 @@ public void visit(BodyDeclaration declaration) { // Init attributes outerType = null; - outerLocalVariableNames.clear(); + syntheticInnerFieldNames.clear(); + syntheticInnerFieldNameToSyntheticInnerFieldReferences.clear(); // Visit methods safeAcceptListDeclaration(bodyDeclaration.getMethodDeclarations()); // Init values bodyDeclaration.setOuterType(outerType); - bodyDeclaration.setOuterLocalVariableNames(outerLocalVariableNames.isEmpty() ? null : new DefaultList<>(outerLocalVariableNames)); - if ((outerType != null) || !outerLocalVariableNames.isEmpty()) { + if (!syntheticInnerFieldNames.isEmpty()) { + bodyDeclaration.setSyntheticInnerFieldNames(new DefaultList<>(syntheticInnerFieldNames)); + } + + if ((outerType != null) || !syntheticInnerFieldNames.isEmpty()) { updateFieldReferencesVisitor.visit(bodyDeclaration); } + + if (!syntheticInnerFieldNameToSyntheticInnerFieldReferences.isEmpty()) { + bodyDeclaration.setSyntheticInnerFieldNameToSyntheticInnerFieldReferences(new HashMap<>(syntheticInnerFieldNameToSyntheticInnerFieldReferences)); + } } @Override @@ -76,12 +89,12 @@ public void visit(ConstructorDeclaration declaration) { ClassFile classFile = cfcd.getClassFile(); ClassFile outerClassFile = classFile.getOuterClassFile(); - outerLocalVariableNames.clear(); + syntheticInnerFieldNames.clear(); + syntheticInnerFieldNameToSyntheticInnerFieldReferences.clear(); // Search synthetic field initialization if (cfcd.getStatements().isList()) { - DefaultList statements = cfcd.getStatements().getList(); - Iterator iterator = statements.iterator(); + Iterator iterator = cfcd.getStatements().iterator(); while (iterator.hasNext()) { Statement statement = iterator.next(); @@ -114,7 +127,8 @@ public void visit(ConstructorDeclaration declaration) { if (name.startsWith("this$")) { outerType = (ObjectType) boe.getRightExpression().getType(); } else if (name.startsWith("val$")) { - outerLocalVariableNames.add(name); + syntheticInnerFieldNames.add(name); + syntheticInnerFieldNameToSyntheticInnerFieldReferences.put(name, new ArrayList<>()); } } } @@ -124,7 +138,7 @@ public void visit(ConstructorDeclaration declaration) { } } - // Remove synthetic parameterTypes + // Remove synthetic parameters BaseFormalParameter parameters = cfcd.getFormalParameters(); if (parameters != null) { @@ -136,14 +150,14 @@ public void visit(ConstructorDeclaration declaration) { list.remove(0); } - int count = outerLocalVariableNames.size(); + int count = syntheticInnerFieldNames.size(); if (count > 0) { // Remove outer local variable reference int size = list.size(); list.subList(size - count, size).clear(); } - } else if ((outerType != null) || !outerLocalVariableNames.isEmpty()) { + } else if ((outerType != null) || !syntheticInnerFieldNames.isEmpty()) { // Remove outer this and outer local variable reference cfcd.setFormalParameters(null); } @@ -234,9 +248,8 @@ public void visit(FieldReferenceExpression expression) { } } } - } else if (outerLocalVariableNames.contains(expression.getName())) { - expression.setName(expression.getName().substring(4)); - expression.setExpression(null); + } else if (syntheticInnerFieldNameToSyntheticInnerFieldReferences.containsKey(expression.getName())) { + syntheticInnerFieldNameToSyntheticInnerFieldReferences.get(expression.getName()).add(expression); } else { super.visit(expression); } @@ -257,13 +270,18 @@ protected Expression updateExpression(Expression expression) { } public static class UpdateNewExpressionVisitor extends AbstractJavaSyntaxVisitor { + protected TypeMaker typeMaker; protected ClassFileBodyDeclaration bodyDeclaration; - protected String superTypeName; - protected HashMap finalLocalVariableNameMap = new HashMap<>(); + protected ClassFile classFile; + protected HashSet finalLocalVariableNameSet = new HashSet<>(); protected DefaultList localClassDeclarations = new DefaultList<>(); protected HashSet newExpressions = new HashSet<>(); protected int lineNumber; + public UpdateNewExpressionVisitor(TypeMaker typeMaker) { + this.typeMaker = typeMaker; + } + @Override public void visit(BodyDeclaration declaration) { bodyDeclaration = (ClassFileBodyDeclaration)declaration; @@ -272,13 +290,13 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(ConstructorDeclaration declaration) { - superTypeName = ((ClassFileConstructorDeclaration)declaration).getClassFile().getSuperTypeName(); - finalLocalVariableNameMap.clear(); + classFile = ((ClassFileConstructorDeclaration)declaration).getClassFile(); + finalLocalVariableNameSet.clear(); localClassDeclarations.clear(); safeAccept(declaration.getStatements()); - if (! finalLocalVariableNameMap.isEmpty()) { + if (! finalLocalVariableNameSet.isEmpty()) { UpdateFinalFieldReferenceVisitor visitor = new UpdateFinalFieldReferenceVisitor(); declaration.getStatements().accept(visitor); @@ -296,11 +314,11 @@ public void visit(ConstructorDeclaration declaration) { @Override public void visit(MethodDeclaration declaration) { - finalLocalVariableNameMap.clear(); + finalLocalVariableNameSet.clear(); localClassDeclarations.clear(); safeAccept(declaration.getStatements()); - if (! finalLocalVariableNameMap.isEmpty()) { + if (! finalLocalVariableNameSet.isEmpty()) { UpdateFinalFieldReferenceVisitor visitor = new UpdateFinalFieldReferenceVisitor(); declaration.getStatements().accept(visitor); @@ -318,11 +336,11 @@ public void visit(MethodDeclaration declaration) { @Override public void visit(StaticInitializerDeclaration declaration) { - finalLocalVariableNameMap.clear(); + finalLocalVariableNameSet.clear(); localClassDeclarations.clear(); safeAccept(declaration.getStatements()); - if (! finalLocalVariableNameMap.isEmpty()) { + if (! finalLocalVariableNameSet.isEmpty()) { declaration.getStatements().accept(new UpdateFinalFieldReferenceVisitor()); } @@ -392,7 +410,9 @@ public void visit(NewExpression expression) { if (parameters != null) { // Remove synthetic parameterTypes - DefaultList outerParameterNames = cfbd.getOuterLocalVariableNames(); + DefaultList syntheticInnerFieldNames = cfbd.getSyntheticInnerFieldNames(); + Map> syntheticInnerFieldNameToSyntheticInnerFieldReferences = + cfbd.getSyntheticInnerFieldNameToSyntheticInnerFieldReferences(); if (parameters.isList()) { DefaultList list = parameters.getList(); @@ -402,25 +422,28 @@ public void visit(NewExpression expression) { list.remove(0); } - if (outerParameterNames != null) { + if (syntheticInnerFieldNames != null) { // Remove outer local variable reference int size = list.size(); - int count = outerParameterNames.size(); + int count = syntheticInnerFieldNames.size(); List lastParameters = list.subList(size - count, size); Iterator parameterIterator = lastParameters.iterator(); - Iterator outerParameterNameIterator = outerParameterNames.iterator(); + Iterator syntheticInnerFieldNameIterator = syntheticInnerFieldNames.iterator(); while (parameterIterator.hasNext()) { - String outerParameterName = outerParameterNameIterator.next(); Expression param = parameterIterator.next(); + String syntheticInnerFieldName = syntheticInnerFieldNameIterator.next(); if (param.getClass() == CastExpression.class) { param = ((CastExpression) param).getExpression(); } if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { - String localVariableName = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable().getName(); - finalLocalVariableNameMap.put(localVariableName, outerParameterName.substring(4)); + AbstractLocalVariable lv = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable(); + String localVariableName = lv.getName(); + finalLocalVariableNameSet.add(localVariableName); + updateSyntheticInnerFieldReferences( + localVariableName, lv.getType(), syntheticInnerFieldNameToSyntheticInnerFieldReferences.get(syntheticInnerFieldName)); } } @@ -429,18 +452,21 @@ public void visit(NewExpression expression) { } else if (cfbd.getOuterType() != null) { // Remove outer this expression.setParameters(null); - } else if (outerParameterNames != null) { + } else if (syntheticInnerFieldNames != null) { // Remove outer local variable reference Expression param = parameters.getFirst(); + String syntheticInnerFieldName = syntheticInnerFieldNames.getFirst(); if (param.getClass() == CastExpression.class) { param = ((CastExpression) param).getExpression(); } if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { - String localVariableName = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable().getName(); - String outerParameterName = outerParameterNames.get(0); - finalLocalVariableNameMap.put(localVariableName, outerParameterName.substring(4)); + AbstractLocalVariable lv = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable(); + String localVariableName = lv.getName(); + finalLocalVariableNameSet.add(localVariableName); + updateSyntheticInnerFieldReferences( + localVariableName, lv.getType(), syntheticInnerFieldNameToSyntheticInnerFieldReferences.get(syntheticInnerFieldName)); expression.setParameters(null); } } @@ -463,6 +489,16 @@ public void visit(NewExpression expression) { } } } + + safeAccept(expression.getParameters()); + } + + protected void updateSyntheticInnerFieldReferences(String name, Type type, List references) { + for (FieldReferenceExpression reference : references) { + reference.setName(name); + reference.setType(type); + reference.setExpression(null); + } } @Override @@ -471,14 +507,15 @@ public void visit(SuperConstructorInvocationExpression expression) { if ((parameters != null) && (parameters.size() > 0)) { // Remove outer 'this' reference parameter - ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(superTypeName); + Type firstParameterType = parameters.getFirst().getType(); - if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { - ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; - ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); + if (firstParameterType.isObject() && ((classFile.getAccessFlags() & ACC_STATIC) == 0) && (bodyDeclaration.getOuterType() != null)) { + TypeMaker.TypeTypes superTypeTypes = typeMaker.makeTypeTypes(classFile.getSuperTypeName()); - if (parameters.getFirst().getType().equals(cfbd.getOuterType())) { - expression.setParameters(removeOuterThisParameter(parameters)); + if ((superTypeTypes != null) && (superTypeTypes.thisType.getClass() == InnerObjectType.class)) { + if (typeMaker.isAssignable(((InnerObjectType)superTypeTypes.thisType).getOuterType(), (ObjectType)firstParameterType)) { + expression.setParameters(removeOuterThisParameter(parameters)); + } } } @@ -538,9 +575,9 @@ protected class UpdateFinalFieldReferenceVisitor extends AbstractJavaSyntaxVisit @Override public void visit(FormalParameter declaration) { - if (finalLocalVariableNameMap.containsKey(declaration.getName())) { + if (finalLocalVariableNameSet.contains(declaration.getName())) { declaration.setFinal(true); - declaration.setName(finalLocalVariableNameMap.get(declaration.getName())); + declaration.setName(declaration.getName()); } } @@ -564,9 +601,9 @@ public void visit(LocalVariableDeclaration declaration) { @Override public void visit(LocalVariableDeclarator declarator) { - if (finalLocalVariableNameMap.containsKey(declarator.getName())) { + if (finalLocalVariableNameSet.contains(declarator.getName())) { fina1 = true; - declarator.setName(finalLocalVariableNameMap.get(declarator.getName())); + declarator.setName(declarator.getName()); } } } @@ -621,7 +658,11 @@ protected BaseStatement addLocalClassDeclarations(BaseStatement statements) { declarationIterator.remove(); } - list.add(statements); + if (statements.isList()) { + list.addAll(statements.getList()); + } else { + list.add(statements.getFirst()); + } statements = list; } else { statements.accept(this); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/MergeTryWithResourcesStatementVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/MergeTryWithResourcesStatementVisitor.java index e6f843bf..24ffb2e9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/MergeTryWithResourcesStatementVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/MergeTryWithResourcesStatementVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -9,7 +9,6 @@ import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileTryStatement; -import org.jd.core.v1.util.DefaultList; import java.util.List; @@ -37,21 +36,17 @@ public void visit(TryStatement statement) { safeAcceptListStatement(statement.getCatchClauses()); safeAccept(statement.getFinallyStatements()); - if (tryStatements.isList()) { - DefaultList sal = tryStatements.getList(); + if (tryStatements.size() == 1) { + Statement first = tryStatements.getFirst(); - if (sal.size() == 1) { - Statement first = sal.getFirst(); + if (first.getClass() == ClassFileTryStatement.class) { + ClassFileTryStatement cfswrs1 = (ClassFileTryStatement)statement; + ClassFileTryStatement cfswrs2 = (ClassFileTryStatement)first; - if (first.getClass() == ClassFileTryStatement.class) { - ClassFileTryStatement cfswrs1 = (ClassFileTryStatement)statement; - ClassFileTryStatement cfswrs2 = (ClassFileTryStatement)first; - - if ((cfswrs2.getResources() != null) && (cfswrs2.getCatchClauses() == null) && (cfswrs2.getFinallyStatements() == null)) { - // Merge 'try' and 'try-with-resources" statements - cfswrs1.setTryStatements(cfswrs2.getTryStatements()); - cfswrs1.addResources(cfswrs2.getResources()); - } + if ((cfswrs2.getResources() != null) && (cfswrs2.getCatchClauses() == null) && (cfswrs2.getFinallyStatements() == null)) { + // Merge 'try' and 'try-with-resources" statements + cfswrs1.setTryStatements(cfswrs2.getTryStatements()); + cfswrs1.addResources(cfswrs2.getResources()); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java new file mode 100644 index 00000000..8986f761 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; + +import java.util.Iterator; +import java.util.Map; + +public class PopulateBindingsWithTypeArgumentVisitor implements TypeArgumentVisitor { + protected TypeArgumentToTypeVisitor typeArgumentToTypeVisitor = new TypeArgumentToTypeVisitor(); + protected TypeMaker typeMaker; + protected Map bindings; + protected BaseTypeArgument current; + + public PopulateBindingsWithTypeArgumentVisitor(TypeMaker typeMaker) { + this.typeMaker = typeMaker; + this.current = null; + } + + public void init(Map bindings, BaseTypeArgument typeArgument) { + this.bindings = bindings; + this.current = typeArgument; + } + + @Override + public void visit(TypeArguments arguments) { + if ((current != null) && current.isTypeArgumentList()) { + Iterator typeArgumentIterator = arguments.iterator(); + Iterator typeGenericArgumentIterator = current.getTypeArgumentList().iterator(); + + while (typeArgumentIterator.hasNext()) { + current = typeGenericArgumentIterator.next(); + typeArgumentIterator.next().accept(this); + } + } + } + + @Override public void visit(GenericType type) { + if (bindings.containsKey(type.getName())) { + TypeArgument typeArgument = bindings.get(type.getName()); + + if (typeArgument == null) { + if (current == null) { + bindings.put(type.getName(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } else { + bindings.put(type.getName(), (TypeArgument) current); + } + } else if ((current != null) && !current.equals(typeArgument)) { + typeArgumentToTypeVisitor.init(); + typeArgument.accept(typeArgumentToTypeVisitor); + Type t1 = typeArgumentToTypeVisitor.getType(); + + typeArgumentToTypeVisitor.init(); + current.accept(typeArgumentToTypeVisitor); + Type t2 = typeArgumentToTypeVisitor.getType(); + + if (!t1.createType(0).equals(t2.createType(0))) { + if (t1.isObject() && t2.isObject()) { + ObjectType ot1 = (ObjectType)t1; + ObjectType ot2 = (ObjectType)t2; + + if (typeMaker.isAssignable(ot1, ot2)) { + bindings.put(type.getName(), typeArgument); + } else if (typeMaker.isAssignable(ot2, ot1)) { + bindings.put(type.getName(), (TypeArgument) current); + } else { + bindings.put(type.getName(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } + } else { + bindings.put(type.getName(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } + } + } + } + } + + @Override + public void visit(WildcardExtendsTypeArgument type) { + if ((current != null) && (current.getClass() == WildcardExtendsTypeArgument.class)) { + current = ((WildcardExtendsTypeArgument) current).getType(); + type.getType().accept(this); + } + } + + @Override + public void visit(WildcardSuperTypeArgument type) { + if ((current != null) && (current.getClass() == WildcardSuperTypeArgument.class)) { + current = ((WildcardSuperTypeArgument) current).getType(); + type.getType().accept(this); + } + } + + @Override + public void visit(ObjectType type) { + if ((current != null) && (type.getTypeArguments() != null)) { + if ((current.getClass() == ObjectType.class) || (current.getClass() == InnerObjectType.class)) { + current = ((ObjectType) current).getTypeArguments(); + type.getTypeArguments().accept(this); + } + } + } + + @Override + public void visit(InnerObjectType type) { + if ((current != null) && (type.getTypeArguments() != null) && (current.getClass() == InnerObjectType.class)) { + current = ((InnerObjectType)current).getTypeArguments(); + type.getTypeArguments().accept(this); + } + } + + @Override public void visit(DiamondTypeArgument argument) {} + @Override public void visit(WildcardTypeArgument type) {} + @Override public void visit(PrimitiveType type) {} +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java new file mode 100644 index 00000000..5cae47d2 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import java.util.Map; + +public class PopulateBindingsWithTypeParameterVisitor implements TypeParameterVisitor { + protected Map bindings = null; + + public void init(Map bindings) { + this.bindings = bindings; + } + + @Override + public void visit(TypeParameter type) { + bindings.put(type.getIdentifier(), null); + } + + @Override + public void visit(TypeParameterWithTypeBounds type) { + bindings.put(type.getIdentifier(), null); + } + + @Override + public void visit(TypeParameters types) { + for (TypeParameter typeParameter : types) { + typeParameter.accept(this); + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java index 5cde68e8..61f0e53f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBlackListNamesVisitor.java @@ -7,14 +7,14 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; -import org.jd.core.v1.model.javasyntax.type.AbstractNopTypeVisitor; +import org.jd.core.v1.model.javasyntax.type.AbstractNopTypeArgumentVisitor; import org.jd.core.v1.model.javasyntax.type.GenericType; import org.jd.core.v1.model.javasyntax.type.InnerObjectType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import java.util.HashSet; -public class PopulateBlackListNamesVisitor extends AbstractNopTypeVisitor { +public class PopulateBlackListNamesVisitor extends AbstractNopTypeArgumentVisitor { protected HashSet blackListNames; public PopulateBlackListNamesVisitor(HashSet blackListNames) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchInTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchInTypeArgumentVisitor.java index eb4f60e1..a87974ea 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchInTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchInTypeArgumentVisitor.java @@ -9,7 +9,7 @@ import org.jd.core.v1.model.javasyntax.type.*; -public class SearchInTypeArgumentVisitor extends AbstractTypeVisitor { +public class SearchInTypeArgumentVisitor extends AbstractTypeArgumentVisitor { protected boolean wildcardFound; protected boolean wildcardSuperOrExtendsTypeFound; protected boolean genericFound; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java new file mode 100644 index 00000000..d6ef77ed --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; + +public class TypeArgumentToTypeVisitor extends AbstractTypeArgumentVisitor { + protected Type type; + + public void init() { + this.type = null; + } + + public Type getType() { + return type; + } + + @Override public void visit(TypeArguments arguments) { type = TYPE_UNDEFINED_OBJECT; } + + @Override public void visit(DiamondTypeArgument argument) { type = TYPE_OBJECT; } + @Override public void visit(WildcardTypeArgument argument) { type = TYPE_OBJECT; } + + @Override public void visit(PrimitiveType type) { this.type = type; } + @Override public void visit(ObjectType type) { this.type = type; } + @Override public void visit(InnerObjectType type) { this.type = type; } + @Override public void visit(GenericType type) { this.type = type; } + + @Override public void visit(WildcardExtendsTypeArgument argument) { argument.getType().accept(this); } + @Override public void visit(WildcardSuperTypeArgument argument) { argument.getType().accept(this); } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java index 34c9221d..2f695112 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -20,6 +20,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeParametersToTypeArgumentsBinder; import org.jd.core.v1.util.DefaultList; import java.util.HashMap; @@ -37,6 +38,24 @@ public boolean init(ClassFileBodyDeclaration bodyDeclaration) { return !bridgeMethodDeclarations.isEmpty(); } + @Override + public void visit(MethodInvocationExpression expression) { + Expression exp = expression.getExpression(); + + expression.setExpression(updateExpression(exp)); + + if (exp != expression.getExpression()) { + TypeParametersToTypeArgumentsBinder.staticBindParameterTypesWithArgumentTypes(expression.getType(), expression); + } + + if (expression.getParameters() != null) { + expression.setParameters(updateBaseExpression(expression.getParameters())); + expression.getParameters().accept(this); + } + + expression.getExpression().accept(this); + } + @SuppressWarnings("unchecked") protected Expression updateExpression(Expression expression) { if (expression.getClass() != ClassFileMethodInvocationExpression.class) { @@ -77,12 +96,12 @@ protected Expression updateExpression(Expression expression) { expression = (parameterTypesCount == 0) ? fre.getExpression() : mie1.getParameters().getFirst(); - return new FieldReferenceExpression(mie1.getLineNumber(), mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()); + return new FieldReferenceExpression(mie1.getLineNumber(), fre.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()); } else if (expClass == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie2 = (MethodInvocationExpression) exp; if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { - return new ClassFileMethodInvocationExpression(mie1.getLineNumber(), null, mie2.getType(), mie2.getExpression(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), mie1.getParameterTypes(), mie1.getParameters()); + return new ClassFileMethodInvocationExpression(null, mie1.getLineNumber(), null, mie2.getType(), mie2.getExpression(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), mie1.getParameterTypes(), mie1.getParameters()); } else { BaseType mie1ParameterTypes = mie1.getParameterTypes(); BaseExpression mie1Parameters = mie1.getParameters(); @@ -108,7 +127,7 @@ protected Expression updateExpression(Expression expression) { } } - return new ClassFileMethodInvocationExpression(mie1.getLineNumber(), null, mie2.getType(), mie1Parameters.getFirst(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameterTypes, newParameters); + return new ClassFileMethodInvocationExpression(null, mie1.getLineNumber(), null, mie2.getType(), mie1Parameters.getFirst(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameterTypes, newParameters); } } else if (expClass == BinaryOperatorExpression.class) { BinaryOperatorExpression boe = (BinaryOperatorExpression) exp; @@ -139,7 +158,7 @@ protected Expression updateExpression(Expression expression) { return new PostOperatorExpression( mie1.getLineNumber(), - new FieldReferenceExpression(mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()), + new FieldReferenceExpression(fre.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()), poe.getOperator()); } else if (expClass == PreOperatorExpression.class) { PreOperatorExpression poe = (PreOperatorExpression)exp; @@ -150,7 +169,7 @@ protected Expression updateExpression(Expression expression) { return new PreOperatorExpression( mie1.getLineNumber(), poe.getOperator(), - new FieldReferenceExpression(mie1.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor())); + new FieldReferenceExpression(fre.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor())); } else if (expClass == IntegerConstantExpression.class) { return exp; } @@ -255,7 +274,7 @@ private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMe if (mie2Parameters.isList()) { int i = 0; - for (Expression parameter : mie2Parameters.getList()) { + for (Expression parameter : mie2Parameters) { if (!checkLocalVariableReference(parameter, i++)) { return false; } @@ -277,7 +296,7 @@ private boolean checkBridgeMethodDeclaration(ClassFileMethodDeclaration bridgeMe if (mie2Parameters.isList()) { int i = 1; - for (Expression parameter : mie2Parameters.getList()) { + for (Expression parameter : mie2Parameters) { if (!checkLocalVariableReference(parameter, i++)) { return false; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 8a84d2dd..06711511 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -39,7 +39,7 @@ public class UpdateIntegerConstantTypeVisitor extends AbstractJavaSyntaxVisitor static { BaseType c = TYPE_CHAR; - BaseType ci = new Types(TYPE_CHAR, TYPE_INT); + BaseType ci = new Types(TYPE_CHAR, TYPE_INT); TYPES.put("java/lang/String:indexOf(I)I", c); TYPES.put("java/lang/String:indexOf(II)I", ci); @@ -490,13 +490,12 @@ protected Expression updateBooleanExpression(Expression expression) { @Override public void visit(TypeReferenceDotClassExpression expression) {} @Override public void visit(ObjectReference reference) {} @Override public void visit(InnerObjectReference reference) {} - @Override public void visit(ArrayTypeArguments type) {} + @Override public void visit(TypeArguments type) {} @Override public void visit(WildcardExtendsTypeArgument type) {} @Override public void visit(ObjectType type) {} @Override public void visit(InnerObjectType type) {} @Override public void visit(WildcardSuperTypeArgument type) {} @Override public void visit(Types list) {} - @Override public void visit(TypeBounds list) {} @Override public void visit(TypeParameterWithTypeBounds type) {} @Override public void visit(BodyDeclaration declaration) {} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java index 95c199d9..bab6ceb4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep1Visitor.java @@ -13,12 +13,12 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; public class UpdateJavaSyntaxTreeStep1Visitor extends AbstractJavaSyntaxVisitor { - protected InitInnerClassVisitor initInnerClassStep1Visitor = new InitInnerClassVisitor(); - protected CreateInstructionsVisitor createInstructionsVisitor; + protected InitInnerClassVisitor initInnerClassStep1Visitor; public UpdateJavaSyntaxTreeStep1Visitor(TypeMaker typeMaker) { createInstructionsVisitor = new CreateInstructionsVisitor(typeMaker); + initInnerClassStep1Visitor = new InitInnerClassVisitor(); } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java index 3661dba8..f37b943b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java @@ -17,17 +17,19 @@ public class UpdateJavaSyntaxTreeStep2Visitor extends AbstractJavaSyntaxVisitor protected static final AggregateFieldsVisitor AGGREGATE_FIELDS_VISITOR = new AggregateFieldsVisitor(); protected static final SortMembersVisitor SORT_MEMBERS_VISITOR = new SortMembersVisitor(); - protected InitInnerClassVisitor.UpdateNewExpressionVisitor initInnerClassStep2Visitor = new InitInnerClassVisitor.UpdateNewExpressionVisitor(); protected InitStaticFieldVisitor initStaticFieldVisitor = new InitStaticFieldVisitor(); protected InitInstanceFieldVisitor initInstanceFieldVisitor = new InitInstanceFieldVisitor(); protected InitEnumVisitor initEnumVisitor = new InitEnumVisitor(); protected RemoveDefaultConstructorVisitor removeDefaultConstructorVisitor = new RemoveDefaultConstructorVisitor(); protected UpdateBridgeMethodVisitor replaceBridgeMethodVisitor = new UpdateBridgeMethodVisitor(); + + protected InitInnerClassVisitor.UpdateNewExpressionVisitor initInnerClassStep2Visitor; protected AddCastExpressionVisitor addCastExpressionVisitor; protected TypeDeclaration typeDeclaration; public UpdateJavaSyntaxTreeStep2Visitor(TypeMaker typeMaker) { + this.initInnerClassStep2Visitor = new InitInnerClassVisitor.UpdateNewExpressionVisitor(typeMaker); this.addCastExpressionVisitor = new AddCastExpressionVisitor(typeMaker); } @@ -42,7 +44,7 @@ public void visit(BodyDeclaration declaration) { typeDeclaration = td; } - // Init visitor + // Init bindTypeArgumentVisitor initStaticFieldVisitor.setInternalTypeName(typeDeclaration.getInternalTypeName()); // Visit declaration diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateTypeVisitor.java index 102af8d3..e76beb1e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateTypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -8,13 +8,13 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; import org.jd.core.v1.model.classfile.attribute.LocalVariableType; -import org.jd.core.v1.model.javasyntax.type.AbstractNopTypeVisitor; +import org.jd.core.v1.model.javasyntax.type.AbstractNopTypeArgumentVisitor; import org.jd.core.v1.model.javasyntax.type.GenericType; import org.jd.core.v1.model.javasyntax.type.InnerObjectType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.LocalVariableSet; -public class UpdateTypeVisitor extends AbstractNopTypeVisitor { +public class UpdateTypeVisitor extends AbstractNopTypeArgumentVisitor { protected LocalVariableSet localVariableSet; protected LocalVariableType localVariableType; diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 40e84854..09b99a27 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -22,6 +22,7 @@ import static org.jd.core.v1.model.classfile.Constants.ACC_SYNTHETIC; public class ClassFileDeserializer { + protected static final int[] EMPTY_INT_ARRAY = new int[0]; public ClassFile loadClassFile(Loader loader, String internalTypeName) throws Exception { return innerLoadClassFile(loader, internalTypeName); @@ -407,7 +408,7 @@ protected BootstrapMethod[] loadBootstrapMethods(ClassFileReader reader) { int[] bootstrapArguments; if (numBootstrapArguments == 0) { - bootstrapArguments = null; + bootstrapArguments = EMPTY_INT_ARRAY; } else { bootstrapArguments = new int[numBootstrapArguments]; for (int j=0; j 0) { - Iterator iterator = declaration.iterator(); + Iterator iterator = declaration.iterator(); iterator.next().accept(this); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index 35b1a8a7..a6462743 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -17,6 +17,7 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.BaseStatement; import org.jd.core.v1.model.javasyntax.statement.LambdaExpressionStatement; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.PrimitiveType; @@ -108,7 +109,10 @@ public void visit(CastExpression expression) { if (expression.isExplicit()) { tokens.addLineNumberToken(expression.getLineNumber()); tokens.add(TextToken.LEFTROUNDBRACKET); - expression.getType().accept(this); + + BaseType type = expression.getType(); + + type.accept(this); tokens.add(TextToken.RIGHTROUNDBRACKET); } @@ -239,7 +243,10 @@ public void visit(InstanceOfExpression expression) { tokens.add(TextToken.SPACE); tokens.add(INSTANCEOF); tokens.add(TextToken.SPACE); - expression.getInstanceOfType().accept(this); + + BaseType type = expression.getInstanceOfType(); + + type.accept(this); } @Override @@ -248,30 +255,29 @@ public void visit(LambdaFormalParametersExpression expression) { if (parameters == null) { tokens.add(TextToken.LEFTRIGHTROUNDBRACKETS); - } else if (parameters.isList()) { - List list = parameters.getList(); - int size = list.size(); + } else { + int size = parameters.size(); switch (size) { case 0: tokens.add(TextToken.LEFTRIGHTROUNDBRACKETS); break; case 1: - list.get(0).accept(this); + parameters.getFirst().accept(this); break; default: tokens.add(TextToken.LEFTROUNDBRACKET); - list.get(0).accept(this); + Iterator iterator = parameters.iterator(); + iterator.next().accept(this); - for (int i = 1; i < size; i++) { + while (iterator.hasNext()) { tokens.add(TextToken.COMMA_SPACE); - list.get(1).accept(this); + iterator.next().accept(this); } + tokens.add(TextToken.RIGHTROUNDBRACKET); break; } - } else { - parameters.accept(this); } visitLambdaBody(expression.getStatements()); @@ -395,7 +401,10 @@ public void visit(NewArray expression) { tokens.addLineNumberToken(expression); tokens.add(NEW); tokens.add(TextToken.SPACE); - expression.getType().accept(this); + + BaseType type = expression.getType(); + + type.accept(this); BaseExpression dimensionExpressionList = expression.getDimensionExpressionList(); int dimension = expression.getType().getDimension(); @@ -406,7 +415,7 @@ public void visit(NewArray expression) { if (dimensionExpressionList != null) { if (dimensionExpressionList.isList()) { - Iterator iterator = dimensionExpressionList.getList().iterator(); + Iterator iterator = dimensionExpressionList.iterator(); while (iterator.hasNext()) { tokens.add(StartBlockToken.START_ARRAY_BLOCK); @@ -430,7 +439,10 @@ public void visit(NewInitializedArray expression) { tokens.addLineNumberToken(expression); tokens.add(NEW); tokens.add(TextToken.SPACE); - expression.getType().accept(this); + + BaseType type = expression.getType(); + + type.accept(this); tokens.add(TextToken.SPACE); expression.getArrayInitializer().accept(this); } @@ -450,7 +462,9 @@ public void visit(NewExpression expression) { tokens.add(TextToken.RIGHTANGLEBRACKET); } - expression.getType().accept(this); + BaseType type = expression.getType(); + + type.accept(this); tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); BaseExpression parameters = expression.getParameters(); @@ -502,7 +516,10 @@ public void visit(NullExpression expression) { public void visit(ObjectTypeReferenceExpression expression) { if (expression.isExplicit()) { tokens.addLineNumberToken(expression); - expression.getObjectType().accept(this); + + BaseType type = expression.getType(); + + type.accept(this); } } @@ -603,7 +620,10 @@ public void visit(ThisExpression expression) { @Override public void visit(TypeReferenceDotClassExpression expression) { tokens.addLineNumberToken(expression); - expression.getTypeDotClass().accept(this); + + BaseType type = expression.getTypeDotClass(); + + type.accept(this); tokens.add(TextToken.DOT); tokens.add(CLASS); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java index acb19db1..df8d5389 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java @@ -13,6 +13,7 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.reference.AnnotationElementValue; import org.jd.core.v1.model.javasyntax.reference.AnnotationReference; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util.JavaFragmentFactory; @@ -29,13 +30,6 @@ public SearchImportsVisitor(String mainInternalName) { this.internalPackagePrefix = (index == -1) ? "" : mainInternalName.substring(0, index + 1); } - @Override - public void visit(AnnotationDeclaration declaration) { - safeAccept(declaration.getAnnotationReferences()); - safeAccept(declaration.getAnnotationDeclarators()); - safeAccept(declaration.getBodyDeclaration()); - } - @Override public void visit(AnnotationReference reference) { super.visit(reference); @@ -48,15 +42,6 @@ public void visit(AnnotationElementValue reference) { add(reference.getType()); } - @Override - public void visit(ClassDeclaration declaration) { - safeAccept(declaration.getSuperType()); - safeAccept(declaration.getTypeParameters()); - safeAccept(declaration.getInterfaces()); - safeAccept(declaration.getAnnotationReferences()); - safeAccept(declaration.getBodyDeclaration()); - } - @Override public void visit(BodyDeclaration declaration) { if (!internalTypeNames.contains(declaration.getInternalTypeName())) { @@ -65,22 +50,6 @@ public void visit(BodyDeclaration declaration) { } } - @Override - public void visit(ConstructorDeclaration declaration) { - safeAccept(declaration.getAnnotationReferences()); - safeAccept(declaration.getFormalParameters()); - safeAccept(declaration.getExceptions()); - safeAccept(declaration.getStatements()); - } - - @Override - public void visit(InterfaceDeclaration declaration) { - safeAccept(declaration.getTypeParameters()); - safeAccept(declaration.getInterfaces()); - safeAccept(declaration.getAnnotationReferences()); - safeAccept(declaration.getBodyDeclaration()); - } - public ImportsFragment getImportsFragment() { importsFragment.initLineCounts(); return importsFragment; @@ -90,13 +59,6 @@ public int getMaxLineNumber() { return maxLineNumber; } - @Override - public void visit(FieldDeclaration declaration) { - safeAccept(declaration.getAnnotationReferences()); - declaration.getType().accept(this); - declaration.getFieldDeclarators().accept(this); - } - @Override public void visit(ObjectType type) { add(type); @@ -153,13 +115,6 @@ public void visit(EnumDeclaration declaration) { safeAccept(declaration.getBodyDeclaration()); } - @Override - public void visit(EnumDeclaration.Constant declaration) { - safeAccept(declaration.getAnnotationReferences()); - safeAccept(declaration.getArguments()); - safeAccept(declaration.getBodyDeclaration()); - } - @Override public void visit(FieldReferenceExpression expression) { if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); @@ -233,7 +188,10 @@ public void visit(NewArray expression) { public void visit(NewExpression expression) { if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); safeAccept(expression.getNonWildcardTypeArguments()); - expression.getType().accept(this); + + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getParameters()); safeAccept(expression.getBodyDeclaration()); } @@ -249,7 +207,10 @@ public void visit(NewInnerExpression expression) { if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); expression.getExpression().accept(this); safeAccept(expression.getNonWildcardTypeArguments()); - expression.getType().accept(this); + + BaseType type = expression.getType(); + + type.accept(this); safeAccept(expression.getParameters()); safeAccept(expression.getBodyDeclaration()); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java index f5f83de3..8cf90334 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java @@ -14,10 +14,10 @@ import org.jd.core.v1.model.javafragment.TokensFragment; import org.jd.core.v1.model.javasyntax.expression.Expression; import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.token.*; import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util.JavaFragmentFactory; -import org.jd.core.v1.util.DefaultList; import java.util.Iterator; import java.util.List; @@ -188,7 +188,9 @@ public void visit(ForEachStatement statement) { tokens.add(TextToken.SPACE); tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); - statement.getType().accept(this); + BaseType type = statement.getType(); + + type.accept(this); tokens.add(TextToken.SPACE); tokens.add(newTextToken(statement.getName())); @@ -303,9 +305,8 @@ protected void visitElseStatements(BaseStatement elseStatements, StartStatements BaseStatement statementList = elseStatements; if (elseStatements.isList()) { - DefaultList list = elseStatements.getList(); - if (list.size() == 1) { - statementList = list.getFirst(); + if (elseStatements.size() == 1) { + statementList = elseStatements.getFirst(); } } @@ -388,7 +389,9 @@ public void visit(LocalVariableDeclarationStatement statement) { tokens.add(TextToken.SPACE); } - statement.getType().accept(this); + BaseType type = statement.getType(); + + type.accept(this); tokens.add(TextToken.SPACE); @@ -588,7 +591,10 @@ public void visit(TryStatement.Resource resource) { Expression expression = resource.getExpression(); tokens.addLineNumberToken(expression); - resource.getType().accept(this); + + BaseType type = resource.getType(); + + type.accept(this); tokens.add(TextToken.SPACE); tokens.add(newTextToken(resource.getName())); tokens.add(TextToken.SPACE_EQUAL_SPACE); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index 518d42d9..243342d5 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -66,19 +66,22 @@ public TypeVisitor(Loader loader, String mainInternalTypeName, int majorVersion, } @Override - public void visit(ArrayTypeArguments list) { - buildTokensForList(list, TextToken.COMMA_SPACE); + public void visit(TypeArguments arguments) { + buildTokensForList(arguments, TextToken.COMMA_SPACE); } @Override - public void visit(DiamondTypeArgument type) {} + public void visit(DiamondTypeArgument argument) {} @Override - public void visit(WildcardExtendsTypeArgument type) { + public void visit(WildcardExtendsTypeArgument argument) { tokens.add(TextToken.QUESTIONMARK_SPACE); tokens.add(EXTENDS); tokens.add(TextToken.SPACE); - type.getType().accept(this); + + BaseType type = argument.getType(); + + type.accept(this); } @Override @@ -110,10 +113,6 @@ public void visit(ObjectType type) { if (typeArguments != null) { visitTypeArgumentList(typeArguments); - } else if (TYPE_CLASS.getInternalName().equals(type.getInternalName())) { - tokens.add(TextToken.LEFTANGLEBRACKET); - tokens.add(TextToken.QUESTIONMARK); - tokens.add(TextToken.RIGHTANGLEBRACKET); } } @@ -124,7 +123,9 @@ public void visit(ObjectType type) { @Override public void visit(InnerObjectType type) { if ((currentInternalTypeName == null) || (!currentInternalTypeName.equals(type.getInternalName()) && !currentInternalTypeName.equals(type.getOuterType().getInternalName()))) { - type.getOuterType().accept(this); + BaseType outerType = type.getOuterType(); + + outerType.accept(this); tokens.add(TextToken.DOT); } @@ -138,10 +139,10 @@ public void visit(InnerObjectType type) { visitDimension(type.getDimension()); } - protected void visitTypeArgumentList(BaseTypeArgument typeArguments) { - if (typeArguments != null) { + protected void visitTypeArgumentList(BaseTypeArgument arguments) { + if (arguments != null) { tokens.add(TextToken.LEFTANGLEBRACKET); - typeArguments.accept(this); + arguments.accept(this); tokens.add(TextToken.RIGHTANGLEBRACKET); } } @@ -162,43 +163,58 @@ protected void visitDimension(int dimension) { } @Override - public void visit(WildcardSuperTypeArgument type) { + public void visit(WildcardSuperTypeArgument argument) { tokens.add(TextToken.QUESTIONMARK_SPACE); tokens.add(SUPER); tokens.add(TextToken.SPACE); - type.getType().accept(this); - } - @Override - @SuppressWarnings("unchecked") - public void visit(Types list) { - buildTokensForList(list, TextToken.COMMA_SPACE); + BaseType type = argument.getType(); + + type.accept(this); } @Override @SuppressWarnings("unchecked") - public void visit(TypeBounds list) { - buildTokensForList(list, TextToken.SPACE_AND_SPACE); + public void visit(Types types) { + buildTokensForList(types, TextToken.COMMA_SPACE); } @Override - public void visit(TypeParameter type) { - tokens.add(newTextToken(type.getIdentifier())); + public void visit(TypeParameter parameter) { + tokens.add(newTextToken(parameter.getIdentifier())); } @Override - public void visit(TypeParameterWithTypeBounds type) { - tokens.add(newTextToken(type.getIdentifier())); + public void visit(TypeParameterWithTypeBounds parameter) { + tokens.add(newTextToken(parameter.getIdentifier())); tokens.add(TextToken.SPACE); tokens.add(EXTENDS); tokens.add(TextToken.SPACE); - type.getTypeBounds().accept(this); + + BaseType types = parameter.getTypeBounds(); + + if (types.isList()) { + buildTokensForList(types.getList(), TextToken.SPACE_AND_SPACE); + } else { + BaseType type = types.getFirst(); + + type.accept(this); + } } @Override @SuppressWarnings("unchecked") public void visit(TypeParameters list) { - buildTokensForList(list, TextToken.COMMA_SPACE); + int size = list.size(); + + if (size > 0) { + list.get(0).accept(this); + + for (int i=1; i void buildTokensForList(List list, TextToken separator) { + protected void buildTokensForList(List list, TextToken separator) { int size = list.size(); if (size > 0) { diff --git a/src/main/java/org/jd/core/v1/util/Base.java b/src/main/java/org/jd/core/v1/util/Base.java index d2a19b4a..21cd8e5b 100644 --- a/src/main/java/org/jd/core/v1/util/Base.java +++ b/src/main/java/org/jd/core/v1/util/Base.java @@ -7,8 +7,11 @@ package org.jd.core.v1.util; +import java.util.Iterator; +import java.util.NoSuchElementException; + @SuppressWarnings("unchecked") -public interface Base { +public interface Base extends Iterable { default boolean isList() { return false; } @@ -28,4 +31,23 @@ default DefaultList getList() { default int size() { return 1; } + + default Iterator iterator() { + return new Iterator() { + private boolean hasNext = true; + public boolean hasNext() { + return hasNext; + } + public T next() { + if (hasNext) { + hasNext = false; + return (T)Base.this; + } + throw new NoSuchElementException(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } } diff --git a/src/main/java/org/jd/core/v1/util/DefaultList.java b/src/main/java/org/jd/core/v1/util/DefaultList.java index 41b11b4e..aa9b30cb 100644 --- a/src/main/java/org/jd/core/v1/util/DefaultList.java +++ b/src/main/java/org/jd/core/v1/util/DefaultList.java @@ -9,20 +9,12 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; @SuppressWarnings("unchecked") public class DefaultList extends ArrayList { - protected static DefaultList EMPTY_LIST = new DefaultList(0) { - public Object set(int var1, Object var2) { - throw new UnsupportedOperationException(); - } - public void add(int var1, Object var2) { - throw new UnsupportedOperationException(); - } - public Object remove(int var1) { - throw new UnsupportedOperationException(); - } - }; + protected static EmptyList EMPTY_LIST = new EmptyList(); public DefaultList() {} @@ -77,4 +69,23 @@ public boolean isList() { public static DefaultList emptyList() { return EMPTY_LIST; } + + protected static class EmptyList extends DefaultList implements Iterator { + public EmptyList() { super(0); } + + public E set(int index, E e) { + throw new UnsupportedOperationException(); + } + public void add(int index, E e) { + throw new UnsupportedOperationException(); + } + public E remove(int index) { + throw new UnsupportedOperationException(); + } + public Iterator iterator() { return this; } + + public boolean hasNext() { return false; } + public E next() { throw new NoSuchElementException(); } + public void remove() { throw new UnsupportedOperationException(); } + } } diff --git a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java index 1e92ae1e..c659a626 100644 --- a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java +++ b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java @@ -77,7 +77,7 @@ public void test() throws Exception { assertNotNull(annotationReference1.getElementValuePairs()); assertTrue(annotationReference1.getElementValuePairs() instanceof ElementValuePairs); - ElementValuePairs elementValuePairArrayList = (ElementValuePairs)annotationReference1.getElementValuePairs(); + ElementValuePairs elementValuePairArrayList = (ElementValuePairs)annotationReference1.getElementValuePairs(); assertEquals(2, elementValuePairArrayList.size()); assertEquals("value", elementValuePairArrayList.getFirst().getName()); diff --git a/src/test/java/org/jd/core/v1/BindTypeParametersToTypeArgumentsVisitorTest.java b/src/test/java/org/jd/core/v1/BindTypeParametersToTypeArgumentsVisitorTest.java new file mode 100644 index 00000000..4fc0dc78 --- /dev/null +++ b/src/test/java/org/jd/core/v1/BindTypeParametersToTypeArgumentsVisitorTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.BindTypeParametersToTypeArgumentsVisitor; +import org.junit.Test; + +import java.util.HashMap; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_INTEGER; + +public class BindTypeParametersToTypeArgumentsVisitorTest extends TestCase { + @Test + public void testGenericTypeI0() throws Exception { + HashMap bindings = new HashMap<>(); + + bindings.put("I", TYPE_INTEGER); + + GenericType genericType = new GenericType("I", 0); + + BindTypeParametersToTypeArgumentsVisitor visitor = new BindTypeParametersToTypeArgumentsVisitor(); + + visitor.setBindings(bindings); + visitor.init(); + genericType.accept(visitor); + BaseType baseType = visitor.getType(); + + assertNotNull(baseType); + assertEquals(baseType, TYPE_INTEGER); + } + + @Test + public void testGenericTypeI3() throws Exception { + HashMap bindings = new HashMap<>(); + + bindings.put("I", TYPE_INTEGER); + + GenericType genericType = new GenericType("I", 3); + + BindTypeParametersToTypeArgumentsVisitor visitor = new BindTypeParametersToTypeArgumentsVisitor(); + + visitor.setBindings(bindings); + visitor.init(); + genericType.accept(visitor); + BaseType baseType = visitor.getType(); + + assertNotNull(baseType); + assertEquals(baseType, TYPE_INTEGER.createType(3)); + } +} \ No newline at end of file diff --git a/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java index 88e8101a..c2e60225 100644 --- a/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java +++ b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -10,6 +10,7 @@ import org.jd.core.v1.model.classfile.ClassFile; import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.model.javasyntax.declaration.FieldDeclarator; +import org.jd.core.v1.model.javasyntax.declaration.MemberDeclarations; import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.MergeMembersUtil; @@ -27,7 +28,7 @@ public class MergeMembersUtilTest { public void testEmptyResult() throws Exception { DefaultList methods = newMethods(); - List result = MergeMembersUtil.merge(null, methods, null); + MemberDeclarations result = MergeMembersUtil.merge(null, methods, null); Assert.assertEquals(methods, result); } @@ -37,14 +38,14 @@ public void testMergeFieldsAndMethods() throws Exception { DefaultList fields = newFields(); DefaultList methods = newMethods(); - List result = MergeMembersUtil.merge(fields, methods, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, methods, null); Assert.assertEquals(fields.size() + methods.size(), result.size()); - Assert.assertEquals(10, result.get(3).getFirstLineNumber()); - Assert.assertEquals(11, result.get(4).getFirstLineNumber()); - Assert.assertEquals(20, result.get(9).getFirstLineNumber()); - Assert.assertEquals(21, result.get(10).getFirstLineNumber()); - Assert.assertEquals(30, result.get(11).getFirstLineNumber()); + Assert.assertEquals(10, ((ClassFileMemberDeclaration)result.get(3)).getFirstLineNumber()); + Assert.assertEquals(11, ((ClassFileMemberDeclaration)result.get(4)).getFirstLineNumber()); + Assert.assertEquals(20, ((ClassFileMemberDeclaration)result.get(9)).getFirstLineNumber()); + Assert.assertEquals(21, ((ClassFileMemberDeclaration)result.get(10)).getFirstLineNumber()); + Assert.assertEquals(30, ((ClassFileMemberDeclaration)result.get(11)).getFirstLineNumber()); } @Test @@ -53,16 +54,16 @@ public void testMergeFieldsMethodsAndInnerTypes_0() throws Exception { DefaultList methods = newMethods(); DefaultList innerTypes = newInnerTypes(0); - List result = MergeMembersUtil.merge(fields, methods, innerTypes); + MemberDeclarations result = MergeMembersUtil.merge(fields, methods, innerTypes); Assert.assertEquals(fields.size() + methods.size() + innerTypes.size(), result.size()); - Assert.assertEquals(10, result.get(3).getFirstLineNumber()); - Assert.assertEquals(11, result.get(4).getFirstLineNumber()); - Assert.assertEquals(20, result.get(9).getFirstLineNumber()); - Assert.assertEquals(21, result.get(10).getFirstLineNumber()); - Assert.assertEquals(30, result.get(11).getFirstLineNumber()); - Assert.assertEquals( 0, result.get(12).getFirstLineNumber()); - Assert.assertEquals( 0, result.get(20).getFirstLineNumber()); + Assert.assertEquals(10, ((ClassFileMemberDeclaration)result.get(3)).getFirstLineNumber()); + Assert.assertEquals(11, ((ClassFileMemberDeclaration)result.get(4)).getFirstLineNumber()); + Assert.assertEquals(20, ((ClassFileMemberDeclaration)result.get(9)).getFirstLineNumber()); + Assert.assertEquals(21, ((ClassFileMemberDeclaration)result.get(10)).getFirstLineNumber()); + Assert.assertEquals(30, ((ClassFileMemberDeclaration)result.get(11)).getFirstLineNumber()); + Assert.assertEquals( 0, ((ClassFileMemberDeclaration)result.get(12)).getFirstLineNumber()); + Assert.assertEquals( 0, ((ClassFileMemberDeclaration)result.get(20)).getFirstLineNumber()); } @Test @@ -71,15 +72,15 @@ public void testMergeFieldsMethodsAndInnerTypes_25() throws Exception { DefaultList methods = newMethods(); DefaultList innerTypes = newInnerTypes(25); - List result = MergeMembersUtil.merge(fields, methods, innerTypes); + MemberDeclarations result = MergeMembersUtil.merge(fields, methods, innerTypes); Assert.assertEquals(fields.size() + methods.size() + innerTypes.size(), result.size()); - Assert.assertEquals(10, result.get(3).getFirstLineNumber()); - Assert.assertEquals(11, result.get(4).getFirstLineNumber()); - Assert.assertEquals(20, result.get(9).getFirstLineNumber()); - Assert.assertEquals(21, result.get(10).getFirstLineNumber()); - Assert.assertEquals(25, result.get(11).getFirstLineNumber()); - Assert.assertEquals(30, result.get(12).getFirstLineNumber()); + Assert.assertEquals(10, ((ClassFileMemberDeclaration)result.get(3)).getFirstLineNumber()); + Assert.assertEquals(11, ((ClassFileMemberDeclaration)result.get(4)).getFirstLineNumber()); + Assert.assertEquals(20, ((ClassFileMemberDeclaration)result.get(9)).getFirstLineNumber()); + Assert.assertEquals(21, ((ClassFileMemberDeclaration)result.get(10)).getFirstLineNumber()); + Assert.assertEquals(25, ((ClassFileMemberDeclaration)result.get(11)).getFirstLineNumber()); + Assert.assertEquals(30, ((ClassFileMemberDeclaration)result.get(12)).getFirstLineNumber()); } @Test @@ -90,7 +91,7 @@ public void testMergeFields() throws Exception { List fields = Arrays.asList(a, b, c); - List result = MergeMembersUtil.merge(fields, null, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, null, null); Assert.assertEquals(fields.size(), result.size()); Assert.assertEquals(a, result.get(0)); @@ -106,7 +107,7 @@ public void testMergeAscendantSortedFields1() throws Exception { List fields = Arrays.asList(a, b, c); - List result = MergeMembersUtil.merge(fields, null, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, null, null); Assert.assertEquals(fields.size(), result.size()); Assert.assertEquals(a, result.get(0)); @@ -125,7 +126,7 @@ public void testMergeAscendantSortedFields2() throws Exception { List fields = Arrays.asList(a, b, c, d, e, f); - List result = MergeMembersUtil.merge(fields, null, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, null, null); Assert.assertEquals(fields.size(), result.size()); Assert.assertEquals(a, result.get(0)); @@ -144,7 +145,7 @@ public void testMergeDescendantSortedFields1() throws Exception { List fields = Arrays.asList(a, b, c); - List result = MergeMembersUtil.merge(fields, null, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, null, null); Assert.assertEquals(fields.size(), result.size()); Assert.assertEquals(c, result.get(0)); @@ -163,7 +164,7 @@ public void testMergeDescendantSortedFields2() throws Exception { List fields = Arrays.asList(a, b, c, d, e, f); - List result = MergeMembersUtil.merge(fields, null, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, null, null); Assert.assertEquals(fields.size(), result.size()); Assert.assertEquals(f, result.get(0)); @@ -182,7 +183,7 @@ public void testMergeUnsortedFields1() throws Exception { List fields = Arrays.asList(a, b, c); - List result = MergeMembersUtil.merge(fields, null, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, null, null); Assert.assertEquals(fields.size(), result.size()); Assert.assertEquals(b, result.get(0)); @@ -201,7 +202,7 @@ public void testMergeUnsortedFields2() throws Exception { List fields = Arrays.asList(a, b, c, d, e, f); - List result = MergeMembersUtil.merge(fields, null, null); + MemberDeclarations result = MergeMembersUtil.merge(fields, null, null); Assert.assertEquals(fields.size(), result.size()); Assert.assertEquals(d, result.get(0)); @@ -254,7 +255,7 @@ protected DefaultList newInnerTypes(int lineNumber) DefaultList fields = new DefaultList<>(); fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), lineNumber)); - ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration("A"); + ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration("A", null, null); bodyDeclaration.setFieldDeclarations(fields); innerTypes.add(new ClassFileClassDeclaration(null, 0, "A", "A", null, null, null, bodyDeclaration)); diff --git a/src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java b/src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java new file mode 100644 index 00000000..0dd95bec --- /dev/null +++ b/src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.PopulateBindingsWithTypeArgumentVisitor; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_INTEGER; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_STRING; +import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.TYPE_INT; + +public class PopulateBindingsForStaticMethodVisitorTest extends TestCase { + @Test + public void test() throws Exception { + // ArrayList method(Set, char); + WildcardExtendsTypeArgument wildcardExtendsString = new WildcardExtendsTypeArgument(TYPE_STRING); + BaseTypeArgument returnedType = new ObjectType("java/util/List", "java.util.List", "List", wildcardExtendsString); + BaseTypeArgument parameterTypes = new TypeArguments(Arrays.asList( + new ObjectType("java/util/Set", "java.util.Set", "Set", TYPE_INTEGER), + TYPE_INT + )); + + // List method(Set set, char) + BaseTypeArgument genericReturnedType = new ObjectType("java/util/List", "java.util.List", "List", new GenericType("O")); + BaseTypeArgument genericParameterTypes = new TypeArguments(Arrays.asList( + new ObjectType("java/util/Set", "java.util.Set", "Set", new GenericType("I")), + TYPE_INT + )); + + // Create bindings + PopulateBindingsWithTypeArgumentVisitor visitor = new PopulateBindingsWithTypeArgumentVisitor(new TypeMaker(new ClassPathLoader())); + HashMap bindings = new HashMap<>(); + bindings.put("I", null); + bindings.put("O", null); + + visitor.init(bindings, returnedType); + genericReturnedType.accept(visitor); + + visitor.init(bindings, parameterTypes); + genericParameterTypes.accept(visitor); + + // Result: bindings[I:Integer, O:? extends String] + assertEquals(bindings.get("I"), TYPE_INTEGER); + assertEquals(bindings.get("O"), wildcardExtendsString); + } +} diff --git a/src/test/java/org/jd/core/v1/SignatureParserTest.java b/src/test/java/org/jd/core/v1/SignatureParserTest.java index de62d0aa..925694c6 100644 --- a/src/test/java/org/jd/core/v1/SignatureParserTest.java +++ b/src/test/java/org/jd/core/v1/SignatureParserTest.java @@ -48,7 +48,10 @@ public void testAnnotatedClass() throws Exception { // Check super type assertNotNull(typeTypes.superType); visitor.reset(); - typeTypes.superType.accept(visitor); + + BaseType superType = typeTypes.superType; + + superType.accept(visitor); String source = visitor.toString(); Assert.assertEquals("java.util.ArrayList", source); @@ -63,7 +66,7 @@ public void testAnnotatedClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = typeMaker.parseFieldSignature(classFile, classFile.getFields()[0]); + BaseType type = typeMaker.parseFieldSignature(classFile, classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -91,8 +94,9 @@ public void testAnnotatedClass() throws Exception { // Check return type assertNotNull(methodTypes.returnedType); + BaseType returnedType = methodTypes.returnedType; visitor.reset(); - methodTypes.returnedType.accept(visitor); + returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("int", source); @@ -121,8 +125,9 @@ public void testAnnotatedClass() throws Exception { // Check return type assertNotNull(methodTypes.returnedType); + returnedType = methodTypes.returnedType; visitor.reset(); - methodTypes.returnedType.accept(visitor); + returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("void", source); @@ -184,9 +189,10 @@ public void testGenericClass() throws Exception { Assert.assertEquals(expected, source); // Check super type - assertNotNull(typeTypes.superType); + BaseType superType = typeTypes.superType; + assertNotNull(superType); visitor.reset(); - typeTypes.superType.accept(visitor); + superType.accept(visitor); source = visitor.toString(); Assert.assertEquals("java.util.ArrayList", source); @@ -201,7 +207,7 @@ public void testGenericClass() throws Exception { // Check field 'list1' // public List> list1 - Type type = typeMaker.parseFieldSignature(classFile, classFile.getFields()[0]); + BaseType type = typeMaker.parseFieldSignature(classFile, classFile.getFields()[0]); visitor.reset(); type.accept(visitor); source = visitor.toString(); @@ -234,8 +240,9 @@ public void testGenericClass() throws Exception { // Check return type assertNotNull(methodTypes.returnedType); + BaseType returnedType = methodTypes.returnedType; visitor.reset(); - methodTypes.returnedType.accept(visitor); + returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("java.util.List", source); @@ -275,8 +282,9 @@ public void testGenericClass() throws Exception { // Check return type assertNotNull(methodTypes.returnedType); + returnedType = methodTypes.returnedType; visitor.reset(); - methodTypes.returnedType.accept(visitor); + returnedType.accept(visitor); source = visitor.toString(); Assert.assertEquals("java.util.List", source); @@ -349,7 +357,7 @@ public void testGenericInnerClass() throws Exception { Assert.assertEquals(ot.getName(), "AbstractMultiValuedMap"); Assert.assertNotNull(ot.getTypeArguments()); - ArrayTypeArguments typeArguments = (ArrayTypeArguments)ot.getTypeArguments(); + TypeArguments typeArguments = (TypeArguments)ot.getTypeArguments(); Assert.assertEquals(typeArguments.size(), 2); Assert.assertEquals(typeArguments.getFirst().toString(), "GenericType{K}"); diff --git a/src/test/java/org/jd/core/v1/TypeTest.java b/src/test/java/org/jd/core/v1/TypeTest.java index 169ff44d..b4af6b97 100644 --- a/src/test/java/org/jd/core/v1/TypeTest.java +++ b/src/test/java/org/jd/core/v1/TypeTest.java @@ -17,7 +17,7 @@ public class TypeTest extends TestCase { @Test public void testSimpleClassOrInterfaceType() throws Exception { - Type scoit = new ObjectType("org/project/Test", "org.project.Test", "Test"); + BaseType scoit = new ObjectType("org/project/Test", "org.project.Test", "Test"); PrintTypeVisitor visitor = new PrintTypeVisitor(); scoit.accept(visitor); @@ -34,7 +34,7 @@ public void testSimpleClassOrInterfaceType2() throws Exception { Type scoit1 = new ObjectType("org/project/Test", "org.project.Test", "Test"); Type scoit2 = new ObjectType( "org/project/OtherTest", "org.project.OtherTest", "OtherTest", - new ArrayTypeArguments( + new TypeArguments( Arrays.asList( scoit1, WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT, @@ -45,8 +45,9 @@ public void testSimpleClassOrInterfaceType2() throws Exception { ); PrintTypeVisitor visitor = new PrintTypeVisitor(); + BaseType baseType2 = scoit2; - scoit2.accept(visitor); + baseType2.accept(visitor); String source = visitor.toString(); @@ -57,7 +58,7 @@ public void testSimpleClassOrInterfaceType2() throws Exception { @Test public void testDiamond() throws Exception { - Type scoit = new ObjectType("org/project/Test", "org.project.Test", "Test", DiamondTypeArgument.DIAMOND); + BaseType scoit = new ObjectType("org/project/Test", "org.project.Test", "Test", DiamondTypeArgument.DIAMOND); PrintTypeVisitor visitor = new PrintTypeVisitor(); @@ -72,7 +73,7 @@ public void testDiamond() throws Exception { @Test public void testInnerClass() throws Exception { - Type scoit = new InnerObjectType("org/project/Test$InnerTest", "org.project.Test.InnerTest", "InnerTest", + BaseType scoit = new InnerObjectType("org/project/Test$InnerTest", "org.project.Test.InnerTest", "InnerTest", new ObjectType("org/project/Test", "org.project.Test", "Test")); PrintTypeVisitor visitor = new PrintTypeVisitor(); diff --git a/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java index b38f956d..267477fe 100644 --- a/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java +++ b/src/test/java/org/jd/core/v1/services/javasyntax/type/visitor/PrintTypeVisitor.java @@ -13,7 +13,7 @@ import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; -public class PrintTypeVisitor implements TypeVisitor { +public class PrintTypeVisitor implements TypeVisitor, TypeArgumentVisitor, TypeParameterVisitor { protected StringBuilder sb = new StringBuilder(); public void reset() { @@ -25,23 +25,35 @@ public String toString() { } @Override - public void visit(ArrayTypeArguments type) { - printList(type, ", "); + public void visit(TypeArguments arguments) { + int size = arguments.size(); + + if (size > 0) { + arguments.get(0).accept(this); + + for (int i=1; i 0) { + parameters.get(0).accept(this); + + for (int i=1; i void printList(List list, String separator) { - int size = list.size(); + protected void printList(List visitables, String separator) { + int size = visitables.size(); if (size > 0) { - list.get(0).accept(this); + visitables.get(0).accept(this); for (int i=1; i Date: Fri, 1 Nov 2019 08:59:33 +0100 Subject: [PATCH 079/211] Fix syntax errors in decompiled sources - score 0 --- .../classfile/attribute/CodeException.java | 4 +- .../ExpressionVariableInitializer.java | 2 +- .../declaration/FieldDeclaration.java | 4 +- .../declaration/FieldDeclarator.java | 2 +- .../reference/AnnotationReference.java | 4 +- .../type/AbstractTypeArgumentVisitor.java | 6 +- .../v1/model/javasyntax/type/GenericType.java | 2 +- .../javasyntax/type/InnerObjectType.java | 2 +- .../v1/model/javasyntax/type/ObjectType.java | 16 +- .../model/javasyntax/type/PrimitiveType.java | 2 +- .../core/v1/model/javasyntax/type/Types.java | 1 - .../javasyntax/type/UnmodifiableTypes.java | 96 +++ .../type/WildcardExtendsTypeArgument.java | 15 + .../type/WildcardSuperTypeArgument.java | 15 + .../javasyntax/type/WildcardTypeArgument.java | 8 +- .../model/cfg/BasicBlock.java | 2 +- .../classfiletojavasyntax/model/cfg/Loop.java | 2 +- .../declaration/ClassFileBodyDeclaration.java | 18 +- .../ClassFileFieldDeclaration.java | 4 +- ...ssFileConstructorInvocationExpression.java | 4 + ...eSuperConstructorInvocationExpression.java | 4 + .../model/localvariable/Frame.java | 11 +- .../localvariable/ObjectLocalVariable.java | 24 +- .../processor/ConvertClassFileProcessor.java | 49 +- .../util/ByteCodeParser.java | 60 +- .../util/LocalVariableMaker.java | 4 +- .../util/LoopStatementMaker.java | 43 +- .../util/StatementMaker.java | 2 +- .../util/StringConcatenationUtil.java | 5 +- .../classfiletojavasyntax/util/TypeMaker.java | 200 ++++- .../TypeParametersToTypeArgumentsBinder.java | 726 ++++++++++-------- .../classfiletojavasyntax/util/WatchDog.java | 2 +- .../visitor/AddCastExpressionVisitor.java | 126 +-- .../BaseTypeToErasedTypeArgumentVisitor.java | 38 + .../BaseTypeToTypeArgumentVisitor.java | 40 + ...ndTypeArgumentsToTypeArgumentsVisitor.java | 192 +++++ ...dTypeParametersToTypeArgumentsVisitor.java | 200 +---- .../visitor/InitInnerClassVisitor.java | 146 ++-- ...pulateBindingsWithTypeArgumentVisitor.java | 109 ++- ...ulateBindingsWithTypeParameterVisitor.java | 5 +- .../visitor/TypeArgumentToTypeVisitor.java | 8 +- .../visitor/UpdateBridgeMethodVisitor.java | 32 +- .../UpdateClassTypeArgumentsVisitor.java | 129 ++++ .../UpdateIntegerConstantTypeVisitor.java | 174 +++-- .../UpdateJavaSyntaxTreeStep2Visitor.java | 3 +- .../visitor/UpdateTypeVisitor.java | 25 +- .../visitor/ExpressionVisitor.java | 13 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 25 +- .../jd/core/v1/JarFileToJavaSourceTest.java | 8 +- .../org/jd/core/v1/MergeMembersUtilTest.java | 2 +- ...ateBindingsForStaticMethodVisitorTest.java | 6 +- ...tTypeMakerTest.java => TypeMakerTest.java} | 200 ++++- .../java/org/jd/core/test/AnonymousClass.java | 198 ++--- 53 files changed, 1893 insertions(+), 1125 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/type/UnmodifiableTypes.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToTypeArgumentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateClassTypeArgumentsVisitor.java rename src/test/java/org/jd/core/v1/{ObjectTypeMakerTest.java => TypeMakerTest.java} (54%) diff --git a/src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java b/src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java index b7da57ad..5258c18b 100644 --- a/src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java +++ b/src/main/java/org/jd/core/v1/model/classfile/attribute/CodeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -51,7 +51,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return 31 * startPc + endPc; + return 969815374 + 31 * startPc + endPc; } @Override diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java index 3b0e02ce..6306b19d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java @@ -43,7 +43,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return expression != null ? expression.hashCode() : 0; + return 25107399 + (expression != null ? expression.hashCode() : 0); } @Override diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java index 98be4071..04ccf1fa 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -65,7 +65,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = flags; + int result = 327494460 + flags; result = 31 * result + (annotationReferences != null ? annotationReferences.hashCode() : 0); result = 31 * result + type.hashCode(); result = 31 * result + fieldDeclarators.hashCode(); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java index 04640ba2..35527578 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclarator.java @@ -70,7 +70,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = name.hashCode(); + int result = 544278669 + name.hashCode(); result = 31 * result + dimension; result = 31 * result + (variableInitializer != null ? variableInitializer.hashCode() : 0); return result; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java index 60c0ccc7..a489cf1e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/reference/AnnotationReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -63,7 +63,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = type.hashCode(); + int result = 970748295 + type.hashCode(); result = 31 * result + (elementValue != null ? elementValue.hashCode() : 0); result = 31 * result + (elementValuePairs != null ? elementValuePairs.hashCode() : 0); return result; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java index 2b73bbd2..fe516dd0 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/AbstractTypeArgumentVisitor.java @@ -10,8 +10,9 @@ public abstract class AbstractTypeArgumentVisitor implements TypeArgumentVisitor { @Override public void visit(TypeArguments arguments) { - for (TypeArgument typeArgument : arguments) + for (TypeArgument typeArgument : arguments) { typeArgument.accept(this); + } } @Override @@ -47,7 +48,8 @@ public void visit(GenericType type) {} public void visit(WildcardTypeArgument argument) {} protected void safeAccept(TypeArgumentVisitable visitable) { - if (visitable != null) + if (visitable != null) { visitable.accept(this); + } } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java index 7d669bc5..1f6a7c48 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java @@ -60,7 +60,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = name.hashCode(); + int result = 991890290 + name.hashCode(); result = 31 * result + dimension; return result; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java index 3b2b7c0c..b13ac1e0 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/InnerObjectType.java @@ -78,7 +78,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = super.hashCode(); + int result = 111476860 + super.hashCode(); result = 31 * result + outerType.hashCode(); return result; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index ae8bf4f7..258d420e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -11,11 +11,13 @@ public class ObjectType implements Type { public static final ObjectType TYPE_BOOLEAN = new ObjectType("java/lang/Boolean", "java.lang.Boolean", "Boolean"); public static final ObjectType TYPE_BYTE = new ObjectType("java/lang/Byte", "java.lang.Byte", "Byte"); public static final ObjectType TYPE_CHARACTER = new ObjectType("java/lang/Character", "java.lang.Character", "Character"); - public static final ObjectType TYPE_CLASS = new ObjectType("java/lang/Class", "java.lang.Class", "Class", WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + public static final ObjectType TYPE_CLASS = new ObjectType("java/lang/Class", "java.lang.Class", "Class"); + public static final ObjectType TYPE_CLASS_WILDCARD = TYPE_CLASS.createType(WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); public static final ObjectType TYPE_DOUBLE = new ObjectType("java/lang/Double", "java.lang.Double", "Double"); public static final ObjectType TYPE_EXCEPTION = new ObjectType("java/lang/Exception", "java.lang.Exception", "Exception"); public static final ObjectType TYPE_FLOAT = new ObjectType("java/lang/Float", "java.lang.Float", "Float"); public static final ObjectType TYPE_INTEGER = new ObjectType("java/lang/Integer", "java.lang.Integer", "Integer"); + public static final ObjectType TYPE_ITERABLE = new ObjectType("java/lang/Iterable", "java.lang.Iterable", "Iterable"); public static final ObjectType TYPE_LONG = new ObjectType("java/lang/Long", "java.lang.Long", "Long"); public static final ObjectType TYPE_MATH = new ObjectType("java/lang/Math", "java.lang.Math", "Math"); public static final ObjectType TYPE_OBJECT = new ObjectType("java/lang/Object", "java.lang.Object", "Object"); @@ -153,7 +155,11 @@ public Type createType(int dimension) { } public ObjectType createType(BaseTypeArgument typeArguments) { - return new ObjectType(internalName, qualifiedName, name, typeArguments, dimension); + if (this.typeArguments == typeArguments) { + return this; + } else { + return new ObjectType(internalName, qualifiedName, name, typeArguments, dimension); + } } @Override @@ -180,7 +186,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = internalName.hashCode(); + int result = 735485092 + internalName.hashCode(); result = 31 * result + (typeArguments != null ? typeArguments.hashCode() : 0); result = 31 * result + dimension; return result; @@ -198,7 +204,9 @@ public void accept(TypeArgumentVisitor visitor) { @Override public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { - if (typeArgument.getClass() != ObjectType.class) { + Class typeArgumentClass = typeArgument.getClass(); + + if ((typeArgumentClass != ObjectType.class) && (typeArgumentClass != InnerObjectType.class)) { return false; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java index 89354672..f9e236ca 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java @@ -145,7 +145,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return flags; + return 750039781 + flags; } @Override diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java index cfe4f941..9aaee8e5 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/Types.java @@ -20,7 +20,6 @@ public Types(int capacity) { public Types(Collection collection) { super(collection); - assert (collection != null) && (collection.size() > 1) : "Uses 'Type' implementation instead"; } @SuppressWarnings("unchecked") diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/UnmodifiableTypes.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/UnmodifiableTypes.java new file mode 100644 index 00000000..7ad5708c --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/UnmodifiableTypes.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.type; + +import java.util.Collection; +import java.util.ListIterator; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +public class UnmodifiableTypes extends Types { + public UnmodifiableTypes() {} + + public UnmodifiableTypes(int capacity) { + super(capacity); + } + + public UnmodifiableTypes(Collection collection) { + super(collection); + } + + @SuppressWarnings("unchecked") + public UnmodifiableTypes(Type type, Type... types) { + super(type, types); + assert (types != null) && (types.length > 0) : "Uses 'Type' implementation instead"; + } + + @Override + public Type removeFirst() { + throw new UnsupportedOperationException(); + } + + @Override + public Type removeLast() { + throw new UnsupportedOperationException(); + } + + @Override + public Type remove(int i) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + protected void removeRange(int i, int i1) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public ListIterator listIterator(int i) { + throw new UnsupportedOperationException(); + } + + @Override + public ListIterator listIterator() { + throw new UnsupportedOperationException(); + } + + @Override + public Type set(int i, Type type) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeIf(Predicate predicate) { + throw new UnsupportedOperationException(); + } + + @Override + public void replaceAll(UnaryOperator unaryOperator) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java index dad3b1a9..2ddfb058 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java @@ -34,6 +34,21 @@ public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { return false; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + WildcardExtendsTypeArgument that = (WildcardExtendsTypeArgument) o; + + return type != null ? type.equals(that.type) : that.type == null; + } + + @Override + public int hashCode() { + return 957014778 + (type != null ? type.hashCode() : 0); + } + @Override public String toString() { return "WildcardExtendsTypeArgument{? extends " + type + "}"; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java index 01e3da46..5d0f6b13 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java @@ -34,6 +34,21 @@ public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { return false; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + WildcardSuperTypeArgument that = (WildcardSuperTypeArgument) o; + + return type != null ? type.equals(that.type) : that.type == null; + } + + @Override + public int hashCode() { + return 979510081 + (type != null ? type.hashCode() : 0); + } + @Override public String toString() { return "WildcardSuperTypeArgument{? super " + type + "}"; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java index ce24abe2..fa586fcd 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java @@ -18,12 +18,12 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public String toString() { - return "Wildcard{?}"; + public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + return true; } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { - return true; + public String toString() { + return "Wildcard{?}"; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/BasicBlock.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/BasicBlock.java index 3c29a641..5c044221 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/BasicBlock.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/BasicBlock.java @@ -380,7 +380,7 @@ public String toString() { @Override public int hashCode() { - return index; + return 378887654 + index; } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/Loop.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/Loop.java index bc47c850..b733c718 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/Loop.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/cfg/Loop.java @@ -56,7 +56,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = start.hashCode(); + int result = 258190310 + start.hashCode(); result = 31 * result + members.hashCode(); result = 31 * result + (end != null ? end.hashCode() : 0); return result; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java index 1dab2925..022c8c29 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java @@ -11,6 +11,7 @@ import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; import org.jd.core.v1.model.javasyntax.declaration.TypeDeclaration; import org.jd.core.v1.model.javasyntax.expression.FieldReferenceExpression; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.TypeArgument; import org.jd.core.v1.util.DefaultList; @@ -28,13 +29,14 @@ public class ClassFileBodyDeclaration extends BodyDeclaration implements ClassFi protected int firstLineNumber; protected ObjectType outerType; protected DefaultList syntheticInnerFieldNames; - protected Map> syntheticInnerFieldNameToSyntheticInnerFieldReferences; protected ClassFileBodyDeclaration outerBodyDeclaration; protected Map bindings; + protected Map typeBounds; - public ClassFileBodyDeclaration(String internalTypeName, Map bindings, ClassFileBodyDeclaration outerBodyDeclaration) { + public ClassFileBodyDeclaration(String internalTypeName, Map bindings, Map typeBounds, ClassFileBodyDeclaration outerBodyDeclaration) { super(internalTypeName, null); this.bindings = bindings; + this.typeBounds = typeBounds; this.outerBodyDeclaration = outerBodyDeclaration; } @@ -132,14 +134,6 @@ public void setSyntheticInnerFieldNames(DefaultList syntheticInnerFieldN this.syntheticInnerFieldNames = syntheticInnerFieldNames; } - public Map> getSyntheticInnerFieldNameToSyntheticInnerFieldReferences() { - return syntheticInnerFieldNameToSyntheticInnerFieldReferences; - } - - public void setSyntheticInnerFieldNameToSyntheticInnerFieldReferences(Map> map) { - this.syntheticInnerFieldNameToSyntheticInnerFieldReferences = map; - } - public ClassFileBodyDeclaration getOuterBodyDeclaration() { return outerBodyDeclaration; } @@ -148,6 +142,10 @@ public Map getBindings() { return bindings; } + public Map getTypeBounds() { + return typeBounds; + } + @Override public String toString() { return "ClassFileBodyDeclaration{firstLineNumber=" + firstLineNumber + "}"; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java index b4e5080a..cd595d93 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -65,7 +65,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = super.hashCode(); + int result = 65247265 + super.hashCode(); result = 31 * result + firstLineNumber; return result; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java index 1c5d7f81..72150997 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileConstructorInvocationExpression.java @@ -23,4 +23,8 @@ public ClassFileConstructorInvocationExpression(int lineNumber, ObjectType type, public BaseType getParameterTypes() { return parameterTypes; } + + public void setParameterTypes(BaseType parameterTypes) { + this.parameterTypes = parameterTypes; + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java index 48c86c81..4dee71c1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileSuperConstructorInvocationExpression.java @@ -23,4 +23,8 @@ public ClassFileSuperConstructorInvocationExpression(int lineNumber, ObjectType public BaseType getParameterTypes() { return parameterTypes; } + + public void setParameterTypes(BaseType parameterTypes) { + this.parameterTypes = parameterTypes; + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index ae47b590..59180539 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -26,6 +26,12 @@ public class Frame { protected static final AbstractLocalVariableComparator ABSTRACT_LOCAL_VARIABLE_COMPARATOR = new AbstractLocalVariableComparator(); + protected static final HashSet CAPITALIZED_JAVA_LANGUAGE_KEYWORDS = new HashSet(Arrays.asList( + "Abstract", "Continue", "For", "New", "Switch", "Assert", "Default", "Goto", "Package", "Synchronized", + "Boolean", "Do", "If", "Private", "This", "Break", "Double", "Implements", "Protected", "Throw", "Byte", "Else", + "Import", "Public", "Throws", "Case", "Enum", "Instanceof", "Return", "Transient", "Catch", "Extends", "Int", + "Short", "Try", "Char", "Final", "Interface", "Static", "Void", "Class", "Finally", "Long", "Strictfp", + "Volatile", "Const", "Float", "Native", "Super", "While")); protected AbstractLocalVariable[] localVariableArray = new AbstractLocalVariable[10]; protected HashMap newExpressions = null; @@ -171,7 +177,7 @@ public void close() { // Update lastType for 'new' expression if (newExpressions != null) { for (Map.Entry entry : newExpressions.entrySet()) { - ObjectType ot1 = (ObjectType) entry.getKey().getType(); + ObjectType ot1 = entry.getKey().getObjectType(); ObjectType ot2 = (ObjectType) entry.getValue().getType(); if ((ot1.getTypeArguments() == null) && (ot2.getTypeArguments() != null)) { @@ -784,6 +790,9 @@ protected void visit(Type type, String str) { sb.append("bool"); } else { uncapitalize(str); + if (CAPITALIZED_JAVA_LANGUAGE_KEYWORDS.contains(str)) { + sb.append("_"); + } } break; default: diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 54b4f4de..ad370b50 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -79,27 +79,11 @@ public String toString() { @Override public boolean isAssignableFrom(Type type) { - if (!type.isPrimitive()) { - if ((type == TYPE_UNDEFINED_OBJECT) || (this.type == TYPE_UNDEFINED_OBJECT) || TYPE_OBJECT.equals(this.type) || this.type.equals(type)) { + if (type.isObject()) { + return typeMaker.isAssignable((ObjectType) this.type, (ObjectType) type); + } else if (type.isGeneric()) { + if (this.type.equals(TYPE_OBJECT)) { return true; - } else if ((this.type.getDimension() == type.getDimension()) && this.type.isObject()) { - ObjectType thisObjectType = (ObjectType) this.type; - - if (type.isObject()) { - ObjectType otherObjectType = (ObjectType) type; - - if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName()) && (thisObjectType.getTypeArguments() != null) && (otherObjectType.getTypeArguments() != null)) { - return thisObjectType.getTypeArguments().isTypeArgumentAssignableFrom(otherObjectType.getTypeArguments()); - } - - if (type.getDimension() == 0) { - if ((thisObjectType.getTypeArguments() == null) ? (otherObjectType.getTypeArguments() == null) : thisObjectType.getTypeArguments().equals(otherObjectType.getTypeArguments())) { - return typeMaker.isAssignable(thisObjectType, otherObjectType); - } - } - } else if (thisObjectType.getInternalName().equals(TYPE_OBJECT.getInternalName())) { - return true; - } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index 7ac37018..61e29765 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -24,6 +24,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.AnnotationConverter; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.PopulateBindingsWithTypeParameterVisitor; import org.jd.core.v1.util.DefaultList; import java.util.Collections; @@ -40,6 +41,7 @@ * Output: {@link org.jd.core.v1.model.javasyntax.CompilationUnit}
*/ public class ConvertClassFileProcessor implements Processor { + protected PopulateBindingsWithTypeParameterVisitor populateBindingsWithTypeParameterVisitor = new PopulateBindingsWithTypeParameterVisitor(); @Override public void process(Message message) throws Exception { @@ -114,41 +116,40 @@ protected ClassFileClassDeclaration convertClassDeclaration(TypeMaker parser, An } protected ClassFileBodyDeclaration convertBodyDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, BaseTypeParameter typeParameters, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { - ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile.getInternalTypeName(), createBindings(classFile, typeParameters, outerClassFileBodyDeclaration), outerClassFileBodyDeclaration); + Map bindings = Collections.emptyMap(); + Map typeBounds = Collections.emptyMap(); - bodyDeclaration.setFieldDeclarations(convertFields(parser, converter, classFile)); - bodyDeclaration.setMethodDeclarations(convertMethods(parser, converter, bodyDeclaration, classFile)); - bodyDeclaration.setInnerTypeDeclarations(convertInnerTypes(parser, converter, classFile, bodyDeclaration)); - - return bodyDeclaration; - } - - protected Map createBindings(ClassFile classFile, BaseTypeParameter typeParameters, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { if (typeParameters == null) { - if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null) && (outerClassFileBodyDeclaration.getBindings() != null)) { - return outerClassFileBodyDeclaration.getBindings(); - } else { - return Collections.emptyMap(); + if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null)) { + bindings = outerClassFileBodyDeclaration.getBindings(); + typeBounds = outerClassFileBodyDeclaration.getTypeBounds(); } } else { - HashMap bindings = new HashMap<>(); + bindings = new HashMap<>(); + typeBounds = new HashMap<>(); + + populateBindingsWithTypeParameterVisitor.init(bindings, typeBounds); + typeParameters.accept(populateBindingsWithTypeParameterVisitor); - if (typeParameters.isList()) { - for (TypeParameter tp : typeParameters) { - String identifier = tp.getIdentifier(); - bindings.put(identifier, new GenericType(identifier)); + for (Map.Entry entry : bindings.entrySet()) { + if (entry.getValue() == null) { + entry.setValue(new GenericType(entry.getKey())); } - } else { - String identifier = typeParameters.getFirst().getIdentifier(); - bindings.put(identifier, new GenericType(identifier)); } - if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null) && (outerClassFileBodyDeclaration.getBindings() != null)) { + if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null)) { bindings.putAll(outerClassFileBodyDeclaration.getBindings()); + typeBounds.putAll(outerClassFileBodyDeclaration.getTypeBounds()); } - - return bindings; } + + ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile.getInternalTypeName(), bindings, typeBounds, outerClassFileBodyDeclaration); + + bodyDeclaration.setFieldDeclarations(convertFields(parser, converter, classFile)); + bodyDeclaration.setMethodDeclarations(convertMethods(parser, converter, bodyDeclaration, classFile)); + bodyDeclaration.setInnerTypeDeclarations(convertInnerTypes(parser, converter, classFile, bodyDeclaration)); + + return bodyDeclaration; } protected List convertFields(TypeMaker parser, AnnotationConverter converter, ClassFile classFile) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index fab08bb4..17912868 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -48,7 +48,6 @@ public class ByteCodeParser { private TypeMaker typeMaker; private LocalVariableMaker localVariableMaker; - private ClassFile classFile; private String internalTypeName; private TypeParametersToTypeArgumentsBinder typeParametersToTypeArgumentsBinder; private AttributeBootstrapMethods attributeBootstrapMethods; @@ -60,7 +59,6 @@ public ByteCodeParser( ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; - this.classFile = classFile; this.internalTypeName = classFile.getInternalTypeName(); this.typeParametersToTypeArgumentsBinder = new TypeParametersToTypeArgumentsBinder(typeMaker, this.internalTypeName, bodyDeclaration, comd); this.attributeBootstrapMethods = classFile.getAttribute("BootstrapMethods"); @@ -728,6 +726,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack".equals(name)) { if (expression1.getClass() == ClassFileNewExpression.class) { - typeParametersToTypeArgumentsBinder.updateNewExpression(expression1, descriptor, methodTypes, parameters); + typeParametersToTypeArgumentsBinder.updateNewExpression((ClassFileNewExpression)expression1, descriptor, methodTypes, parameters); } else if (ot.getDescriptor().equals(expression1.getType().getDescriptor())) { statements.add(new ExpressionStatement(typeParametersToTypeArgumentsBinder.newConstructorInvocationExpression( lineNumber, ot, descriptor, methodTypes, parameters))); @@ -806,16 +805,20 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { - ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); - - typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(vre.getType(), valueRef); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(localVariable.getType(), valueRef); + localVariable.typeOnRight(valueRef.getType()); + ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); Expression oldValueRef = valueRef; if (valueRef.getClass() == NewArray.class) { @@ -1577,15 +1572,21 @@ private static void parseIINC(Statements statements, DefaultStack st statements.add(new ExpressionStatement(expression)); } - private static void parseIF(DefaultStack stack, int lineNumber, BasicBlock basicBlock, String operator1, String operator2, int priority) { + private void parseIF(DefaultStack stack, int lineNumber, BasicBlock basicBlock, String operator1, String operator2, int priority) { Expression expression = stack.pop(); if (expression.getClass() == ClassFileCmpExpression.class) { ClassFileCmpExpression cmp = (ClassFileCmpExpression)expression; + + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(cmp.getLeftExpression().getType(), cmp.getLeftExpression()); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(cmp.getRightExpression().getType(), cmp.getRightExpression()); + stack.push(new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, cmp.getLeftExpression(), (basicBlock.mustInverseCondition() ? operator1 : operator2), cmp.getRightExpression(), priority)); } else if (expression.getType().isPrimitive()) { PrimitiveType pt = (PrimitiveType)expression.getType(); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(pt, expression); + switch (pt.getJavaPrimitiveFlags()) { case FLAG_BOOLEAN: if (basicBlock.mustInverseCondition() ^ "==".equals(operator1)) @@ -1837,7 +1838,7 @@ private static Expression newIntegerOrBooleanBinaryOperatorExpression(int lineNu * Operators = { "==", "!=" } * See "Numerical Equality Operators == and !=": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.21.1 */ - private static Expression newIntegerOrBooleanComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + private Expression newIntegerOrBooleanComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { Class leftClass = leftExpression.getClass(); Class rightClass = rightExpression.getClass(); @@ -1866,6 +1867,9 @@ private static Expression newIntegerOrBooleanComparisonOperatorExpression(int li } } + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(leftExpression.getType(), rightExpression); + typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(rightExpression.getType(), leftExpression); + return new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, leftExpression, operator, rightExpression, priority); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 4ba84e46..668e09b0 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -347,7 +347,7 @@ public boolean isCompatible(AbstractLocalVariable lv, Type valueType) { BaseTypeArgument valueTypeArguments = valueObjectType.getTypeArguments(); if ((lvTypeArguments == null) || (valueTypeArguments == null)) { - return typeMaker.isAssignable(lvObjectType, valueObjectType); + return typeMaker.isRawTypeAssignable(lvObjectType, valueObjectType); } searchInTypeArgumentVisitor.init(); @@ -358,7 +358,7 @@ public boolean isCompatible(AbstractLocalVariable lv, Type valueType) { valueTypeArguments.accept(searchInTypeArgumentVisitor); if (searchInTypeArgumentVisitor.containsGeneric()) { - return typeMaker.isAssignable(lvObjectType, valueObjectType); + return typeMaker.isRawTypeAssignable(lvObjectType, valueObjectType); } } } else if (lv.getType().isGeneric() && valueObjectType.getInternalName().equals(ObjectType.TYPE_OBJECT.getInternalName())) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index e23b12c8..f3ce3c3e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -31,6 +31,7 @@ import java.util.ListIterator; import static org.jd.core.v1.model.javasyntax.statement.ContinueStatement.CONTINUE; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_ITERABLE; public class LoopStatementMaker { protected static final RemoveLastContinueStatementVisitor REMOVE_LAST_CONTINUE_STATEMENT_VISITOR = new RemoveLastContinueStatementVisitor(); @@ -639,28 +640,32 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker item.setDeclared(true); localVariableMaker.removeLocalVariable(syntheticIterator); - ObjectType listType = (ObjectType)list.getType(); + Type type = list.getType(); - if (listType.getTypeArguments() == null) { - if (item.getType().isObject()) { - ObjectType ot = (ObjectType)item.getType(); + if (type.isObject()) { + ObjectType listType = (ObjectType)type; - if (ot.getTypeArguments() != null) { - TypeParametersToTypeArgumentsBinder.staticBindParameterTypesWithArgumentTypes(ot, list); + if (listType.getTypeArguments() == null) { + if (item.getType().isObject()) { + ObjectType ot = (ObjectType) item.getType(); + + if (ot.getTypeArguments() != null) { + list = new CastExpression(TYPE_ITERABLE.createType(ot), list); + } } - } - } else { - CreateTypeFromTypeArgumentVisitor visitor2 = new CreateTypeFromTypeArgumentVisitor(); - listType.getTypeArguments().accept(visitor2); - Type type = visitor2.getType(); - - if (type != null) { - if (ObjectType.TYPE_OBJECT.equals(item.getType())) { - ((ObjectLocalVariable)item).setType(type); - } else if (item.getType().isGeneric()) { - ((GenericLocalVariable)item).setType((GenericType)type); - } else { - item.typeOnRight(type); + } else { + CreateTypeFromTypeArgumentVisitor visitor2 = new CreateTypeFromTypeArgumentVisitor(); + listType.getTypeArguments().accept(visitor2); + type = visitor2.getType(); + + if (type != null) { + if (ObjectType.TYPE_OBJECT.equals(item.getType())) { + ((ObjectLocalVariable) item).setType(type); + } else if (item.getType().isGeneric()) { + ((GenericLocalVariable) item).setType((GenericType) type); + } else { + item.typeOnRight(type); + } } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index b998b466..d4b42fe8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -889,7 +889,7 @@ protected TernaryOperatorExpression newTernaryOperatorExpression(int lineNumber, } else if ((flags & FLAG_LONG) != 0) { type = TYPE_LONG; } else { - type = TYPE_INT; + type = MAYBE_BOOLEAN_TYPE; } } else if (expressionTrueType.isObject() && expressionFalseType.isObject()) { ObjectType ot1 = (ObjectType)expressionTrueType; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java index b272dda9..e274d425 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java @@ -40,10 +40,11 @@ public static Expression create(Expression expression, int lineNumber, String ty } if (expr.getClass() == ClassFileNewExpression.class) { - ClassFileNewExpression ne = (ClassFileNewExpression) expr; - String internalTypeName = ne.getType().getDescriptor(); + String internalTypeName = expr.getType().getDescriptor(); if ("Ljava/lang/StringBuilder;".equals(internalTypeName) || "Ljava/lang/StringBuffer;".equals(internalTypeName)) { + ClassFileNewExpression ne = (ClassFileNewExpression) expr; + if (ne.getParameters() == null) { if (!firstParameterHaveGenericType) { return concatenatedStringExpression; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index 4b3b8d37..564e5bf8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.Iterator; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; /* @@ -56,6 +57,9 @@ public class TypeMaker { private HashMap internalTypeNameMethodNameDescriptorToMethodTypes = new HashMap<>(1024); private HashMap signatureToMethodTypes = new HashMap<>(1024); + private HashMap assignableRawTypes = new HashMap<>(1024); + private HashMap superParameterizedObjectTypes = new HashMap<>(1024); + private HashMap hierarchy = new HashMap<>(1024); private ClassPathLoader classPathLoader = new ClassPathLoader(); private Loader loader; @@ -123,7 +127,7 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { if (length == 1) { typeTypes.interfaces = makeFromInternalTypeName(interfaceTypeNames[0]); } else { - Types list = new Types(length); + UnmodifiableTypes list = new UnmodifiableTypes(length); for (String interfaceTypeName : interfaceTypeNames) { list.add(makeFromInternalTypeName(interfaceTypeName)); } @@ -145,7 +149,7 @@ public TypeTypes parseClassFileSignature(ClassFile classFile) { if (nextInterface == null) { typeTypes.interfaces = firstInterface; } else { - Types list = new Types(classFile.getInterfaceTypeNames().length); + UnmodifiableTypes list = new UnmodifiableTypes(classFile.getInterfaceTypeNames().length); list.add(firstInterface); @@ -252,8 +256,8 @@ private MethodTypes parseMethodSignature(String descriptor, String signature, St } else if (mtDescriptor.parameterTypes.size() == mtSignature.parameterTypes.size()) { return mtSignature; } else { - Types parameterTypes = new Types(mtDescriptor.parameterTypes.getList()); - parameterTypes.subList(parameterTypes.size() - mtSignature.parameterTypes.size(), parameterTypes.size()).clear(); + UnmodifiableTypes parameterTypes = new UnmodifiableTypes(mtDescriptor.parameterTypes.getList().subList( + 0, mtDescriptor.parameterTypes.size() - mtSignature.parameterTypes.size())); parameterTypes.addAll(mtSignature.parameterTypes.getList()); MethodTypes mt = new MethodTypes(); @@ -309,7 +313,7 @@ private MethodTypes parseMethodSignature(String signature, String[] exceptionTyp methodTypes.parameterTypes = null; } else { Type nextParameterType = parseReferenceTypeSignature(reader); - Types types = new Types(); + UnmodifiableTypes types = new UnmodifiableTypes(); types.add(firstParameterType); @@ -337,7 +341,7 @@ private MethodTypes parseMethodSignature(String signature, String[] exceptionTyp if (exceptionTypeNames.length == 1) { methodTypes.exceptions = makeFromInternalTypeName(exceptionTypeNames[0]); } else { - Types list = new Types(exceptionTypeNames.length); + UnmodifiableTypes list = new UnmodifiableTypes(exceptionTypeNames.length); for (String exceptionTypeName : exceptionTypeNames) { list.add(makeFromInternalTypeName(exceptionTypeName)); @@ -352,7 +356,7 @@ private MethodTypes parseMethodSignature(String signature, String[] exceptionTyp if (nextException == null) { methodTypes.exceptions = firstException; } else { - Types list = new Types(); + UnmodifiableTypes list = new UnmodifiableTypes(); list.add(firstException); @@ -430,7 +434,7 @@ private TypeParameter parseTypeParameter(SignatureReader reader) { // Parser bounds Type firstBound = null; - Types types = null; + UnmodifiableTypes types = null; while (reader.nextEqualsTo(':')) { // Skip ':' @@ -442,7 +446,7 @@ private TypeParameter parseTypeParameter(SignatureReader reader) { if (firstBound == null) { firstBound = bound; } else if (types == null) { - types = new Types(); + types = new UnmodifiableTypes(); types.add(firstBound); types.add(bound); } else { @@ -859,49 +863,181 @@ private ObjectType create(String internalTypeName) { return ot; } - public boolean isAssignable(ObjectType parent, ObjectType child) { - if (parent == TYPE_UNDEFINED_OBJECT) { + public ObjectType searchSuperParameterizedType(ObjectType superObjectType, ObjectType objectType) { + if ((superObjectType == TYPE_UNDEFINED_OBJECT) || superObjectType.equals(TYPE_OBJECT) || superObjectType.equals(objectType)) { + return objectType; + } else if ((superObjectType.getDimension() > 0) || (objectType.getDimension() > 0)) { + return null; + } else { + String superInternalTypeName = superObjectType.getInternalName(); + long superHashCode = superInternalTypeName.hashCode() * 31; + return searchSuperParameterizedType(superHashCode, superInternalTypeName, objectType); + } + } + + public boolean isAssignable(ObjectType left, ObjectType right) { + if ((left == TYPE_UNDEFINED_OBJECT) || left.equals(TYPE_OBJECT) || left.equals(right)) { return true; - } else if (parent.getDimension() > 0) { - return (parent.getDimension() == child.getDimension()) && parent.getInternalName().equals(child.getInternalName()); - } else if (child.getDimension() > 0) { + } else if ((left.getDimension() > 0) || (right.getDimension() > 0)) { return false; } else { - String parentInternalName = parent.getInternalName(); - String childInternalName = child.getInternalName(); + String leftInternalTypeName = left.getInternalName(); + long leftHashCode = leftInternalTypeName.hashCode() * 31; + ObjectType ot = searchSuperParameterizedType(leftHashCode, leftInternalTypeName, right); - if (parentInternalName.equals(childInternalName) || parentInternalName.equals("java/lang/Object")) { - return true; + if ((ot != null) && leftInternalTypeName.equals(ot.getInternalName())) { + if ((left.getTypeArguments() == null) || (ot.getTypeArguments() == null)) { + return true; + } else { + return left.getTypeArguments().isTypeArgumentAssignableFrom(ot.getTypeArguments()); + } } - return recursiveIsAssignable(parentInternalName, childInternalName); + return false; + } + } + + private ObjectType searchSuperParameterizedType(long superHashCode, String superInternalTypeName, ObjectType objectType) { + if (objectType.equals(TYPE_OBJECT)) { + return null; + } + + Long key = Long.valueOf(superHashCode + objectType.hashCode()); + + if (superParameterizedObjectTypes.containsKey(key)) { + return superParameterizedObjectTypes.get(key); + } + + String rightInternalName = objectType.getInternalName(); + + if (superInternalTypeName.equals(rightInternalName)) { + superParameterizedObjectTypes.put(key, objectType); + return objectType; + } + + TypeTypes rightTypeTypes = makeTypeTypes(rightInternalName); + + if (rightTypeTypes != null) { + if ((rightTypeTypes.typeParameters == null) || (objectType.getTypeArguments() == null)) { + if (rightTypeTypes.superType != null) { + ObjectType ot = searchSuperParameterizedType(superHashCode, superInternalTypeName, rightTypeTypes.superType.createType(null)); + + if (ot != null) { + superParameterizedObjectTypes.put(key, ot); + return ot; + } + } + if (rightTypeTypes.interfaces != null) { + for (Type interfaze : rightTypeTypes.interfaces) { + ObjectType ot = searchSuperParameterizedType(superHashCode, superInternalTypeName, ((ObjectType)interfaze).createType(null)); + + if (ot != null) { + superParameterizedObjectTypes.put(key, ot); + return ot; + } + } + } + } else { + BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); + HashMap bindings = new HashMap<>(); + + if (rightTypeTypes.typeParameters.isList()) { + Iterator iteratorTypeParameter = rightTypeTypes.typeParameters.iterator(); + Iterator iteratorTypeArgument = objectType.getTypeArguments().getTypeArgumentList().iterator(); + + while (iteratorTypeParameter.hasNext()) { + bindings.put(iteratorTypeParameter.next().getIdentifier(), iteratorTypeArgument.next()); + } + } else { + bindings.put(rightTypeTypes.typeParameters.getFirst().getIdentifier(), objectType.getTypeArguments().getTypeArgumentFirst()); + } + + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + + if (rightTypeTypes.superType != null) { + bindTypeParametersToTypeArgumentsVisitor.init(); + rightTypeTypes.superType.accept(bindTypeParametersToTypeArgumentsVisitor); + ObjectType ot = (ObjectType) bindTypeParametersToTypeArgumentsVisitor.getType(); + ot = searchSuperParameterizedType(superHashCode, superInternalTypeName, ot); + + if (ot != null) { + superParameterizedObjectTypes.put(key, ot); + return ot; + } + } + if (rightTypeTypes.interfaces != null) { + for (Type interfaze : rightTypeTypes.interfaces) { + bindTypeParametersToTypeArgumentsVisitor.init(); + interfaze.accept(bindTypeParametersToTypeArgumentsVisitor); + ObjectType ot = (ObjectType) bindTypeParametersToTypeArgumentsVisitor.getType(); + ot = searchSuperParameterizedType(superHashCode, superInternalTypeName, ot); + + if (ot != null) { + superParameterizedObjectTypes.put(key, ot); + return ot; + } + } + } + } + } + + superParameterizedObjectTypes.put(key, null); + return null; + } + + public boolean isRawTypeAssignable(ObjectType left, ObjectType right) { + if ((left == TYPE_UNDEFINED_OBJECT) || left.equals(TYPE_OBJECT) || left.equals(right)) { + return true; + } else if ((left.getDimension() > 0) || (right.getDimension() > 0)) { + return false; + } else { + String leftInternalName = left.getInternalName(); + String rightInternalName = right.getInternalName(); + + if (leftInternalName.equals(rightInternalName)) { + return true; + } else { + return isRawTypeAssignable(leftInternalName.hashCode() * 31, leftInternalName, rightInternalName); + } } } @SuppressWarnings("unchecked") - private boolean recursiveIsAssignable(String parentInternalName, String childInternalName) { - if (childInternalName.equals("java/lang/Object")) + private boolean isRawTypeAssignable(long leftHashCode, String leftInternalName, String rightInternalName) { + if (rightInternalName.equals("java/lang/Object")) { return false; + } + + Long key = Long.valueOf(leftHashCode + rightInternalName.hashCode()); - String[] superClassAndInterfaceNames = hierarchy.get(childInternalName); + if (assignableRawTypes.containsKey(key)) { + return assignableRawTypes.get(key).booleanValue(); + } + + String[] superClassAndInterfaceNames = hierarchy.get(rightInternalName); if (superClassAndInterfaceNames == null) { - loadType(childInternalName); - superClassAndInterfaceNames = hierarchy.get(childInternalName); + loadType(rightInternalName); + superClassAndInterfaceNames = hierarchy.get(rightInternalName); } if (superClassAndInterfaceNames != null) { for (String name : superClassAndInterfaceNames) { - if (parentInternalName.equals(name)) + if (leftInternalName.equals(name)) { + assignableRawTypes.put(key, Boolean.TRUE); return true; + } } for (String name : superClassAndInterfaceNames) { - if (recursiveIsAssignable(parentInternalName, name)) + if (isRawTypeAssignable(leftHashCode, leftInternalName, name)) { + assignableRawTypes.put(key, Boolean.TRUE); return true; + } } } + assignableRawTypes.put(key, Boolean.FALSE); return false; } @@ -974,7 +1110,7 @@ private TypeTypes makeTypeTypes(String internalTypeName, byte[] data) throws Exc break; default: int length = superClassAndInterfaceNames.length; - Types list = new Types(length-1); + UnmodifiableTypes list = new UnmodifiableTypes(length-1); for (int i=1; i contextualBindings; + protected Map contextualTypeBounds; public TypeParametersToTypeArgumentsBinder( TypeMaker typeMaker, String internalTypeName, ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { this.typeMaker = typeMaker; this.internalTypeName = internalTypeName; + this.staticMethod = ((comd.getFlags() & FLAG_STATIC) != 0); this.populateBindingsWithTypeArgumentVisitor = new PopulateBindingsWithTypeArgumentVisitor(typeMaker); - if ((comd.getFlags() & FLAG_STATIC) == 0) { - this.contextualBindings = bodyDeclaration.getBindings(); - } else { + if (this.staticMethod) { this.contextualBindings = Collections.emptyMap(); + this.contextualTypeBounds = Collections.emptyMap(); + } else { + this.contextualBindings = bodyDeclaration.getBindings(); + this.contextualTypeBounds = bodyDeclaration.getTypeBounds(); } if (comd.getTypeParameters() != null) { HashMap bindings = new HashMap<>(); + Map typeBounds = new HashMap<>(); bindings.putAll(this.contextualBindings); + typeBounds.putAll(this.contextualTypeBounds); - populateBindingsWithTypeParameterVisitor.init(bindings); + populateBindingsWithTypeParameterVisitor.init(bindings, typeBounds); comd.getTypeParameters().accept(populateBindingsWithTypeParameterVisitor); for (HashMap.Entry entry : bindings.entrySet()) { @@ -62,6 +66,7 @@ public TypeParametersToTypeArgumentsBinder( } this.contextualBindings = bindings; + this.contextualTypeBounds = typeBounds; } } @@ -69,45 +74,12 @@ public ClassFileConstructorInvocationExpression newConstructorInvocationExpressi int lineNumber, ObjectType objectType, String descriptor, TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { - BaseType parameterTypes = methodTypes.parameterTypes; - Map bindings = contextualBindings; - - if ((parameterTypes != null) && (methodTypes.typeParameters != null)) { - bindings = new HashMap<>(); - bindings.putAll(contextualBindings); - - populateBindingsWithTypeParameterVisitor.init(bindings); - methodTypes.typeParameters.accept(populateBindingsWithTypeParameterVisitor); + BaseType parameterTypes = clone(methodTypes.parameterTypes); + Map bindings = createBindings(null, null, null, methodTypes.typeParameters, PrimitiveType.TYPE_VOID, null, parameterTypes, parameters); - if (parameterTypes.size() > 1) { - Iterator parametersIterator = parameters.iterator(); - Iterator parameterTypesIterator = parameterTypes.iterator(); + parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes); + bindParameterTypesWithArgumentTypes(parameterTypes, parameters); - while (parametersIterator.hasNext()) { - Expression parameter = parametersIterator.next(); - Type parameterType = parameterTypesIterator.next(); - - if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { - populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); - parameterType.accept(populateBindingsWithTypeArgumentVisitor); - } - } - } else if (parameterTypes.size() > 0) { - Expression parameter = parameters.getFirst(); - - if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { - populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); - parameterTypes.getFirst().accept(populateBindingsWithTypeArgumentVisitor); - } - } - } - - if (!bindings.isEmpty() && !bindings.containsValue(null)) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); - parameterTypes = bindParameterTypesWithArgumentTypes(TYPE_OBJECT, parameterTypes); - } - - parameters = prepareParameters(parameters, parameterTypes); return new ClassFileConstructorInvocationExpression(lineNumber, objectType, descriptor, parameterTypes, parameters); } @@ -115,7 +87,7 @@ public ClassFileSuperConstructorInvocationExpression newSuperConstructorInvocati int lineNumber, ObjectType objectType, String descriptor, TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { - BaseType parameterTypes = methodTypes.parameterTypes; + BaseType parameterTypes = clone(methodTypes.parameterTypes); Map bindings = contextualBindings; TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(internalTypeName); @@ -123,424 +95,502 @@ public ClassFileSuperConstructorInvocationExpression newSuperConstructorInvocati TypeMaker.TypeTypes superTypeTypes = typeMaker.makeTypeTypes(objectType.getInternalName()); if (superTypeTypes != null) { - bindings = createBindings(superTypeTypes.typeParameters, typeTypes.superType.getTypeArguments(), methodTypes.typeParameters); + BaseTypeParameter typeParameters = superTypeTypes.typeParameters; + BaseTypeArgument typeArguments = typeTypes.superType.getTypeArguments(); + BaseTypeParameter methodTypeParameters = methodTypes.typeParameters; + + bindings = createBindings(null, typeParameters, typeArguments, methodTypeParameters, PrimitiveType.TYPE_VOID, null, parameterTypes, parameters); } } - if (!bindings.isEmpty()) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); - parameterTypes = bindParameterTypesWithArgumentTypes(objectType, methodTypes.parameterTypes); - } + parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes); + bindParameterTypesWithArgumentTypes(parameterTypes, parameters); - parameters = prepareParameters(parameters, parameterTypes); return new ClassFileSuperConstructorInvocationExpression(lineNumber, objectType, descriptor, parameterTypes, parameters); } public ClassFileMethodInvocationExpression newMethodInvocationExpression( int lineNumber, Expression expression, ObjectType objectType, String name, String descriptor, TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { + return new ClassFileMethodInvocationExpression( + this, lineNumber, methodTypes.typeParameters, methodTypes.returnedType, expression, + objectType.getInternalName(), name, descriptor, clone(methodTypes.parameterTypes), parameters); + } - Type returnedType = methodTypes.returnedType; - BaseType parameterTypes = methodTypes.parameterTypes; + public FieldReferenceExpression newFieldReferenceExpression( + int lineNumber, Type type, Expression expression, ObjectType objectType, String name, String descriptor) { - if (methodTypes.typeParameters == null) { - Map bindings = contextualBindings; + Type expressionType = expression.getType(); - if (expression.getClass() != ThisExpression.class) { - Type expressionType = expression.getType(); + if (expressionType.isObject()) { + ObjectType expressionObjectType = (ObjectType) expressionType; - if (expressionType.isObject()) { - ObjectType expressionObjectType = (ObjectType) expressionType; - TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(objectType.getInternalName()); + if (staticMethod || !expressionObjectType.getInternalName().equals(internalTypeName)) { + if (type.isObject()) { + ObjectType ot = (ObjectType) type; - if (typeTypes != null) { - BaseTypeParameter typeParameters = typeTypes.typeParameters; - BaseTypeArgument typeArguments; + if (ot.getTypeArguments() != null) { + Map bindings; + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(expressionObjectType.getInternalName()); - if (expression.getClass() == SuperExpression.class) { - typeTypes = typeMaker.makeTypeTypes(internalTypeName); - typeArguments = typeTypes.superType.getTypeArguments(); + if (typeTypes == null) { + bindings = contextualBindings; } else { - typeArguments = expressionObjectType.getTypeArguments(); - } + BaseTypeParameter typeParameters = typeTypes.typeParameters; + BaseTypeArgument typeArguments = expressionObjectType.getTypeArguments(); - if ((typeParameters != null) && (typeArguments == null)) { - Class expressionClass = expression.getClass(); - - if ((expressionClass == ObjectTypeReferenceExpression.class) && name.startsWith("access$")) { - // Bridge method => Do not bind - bindings = Collections.emptyMap(); - } else if ((expressionClass == ClassFileMethodInvocationExpression.class) && ((ClassFileMethodInvocationExpression)expression).getName().startsWith("access$")) { - // Bridge method => Do not bind - bindings = Collections.emptyMap(); - } else if ((expressionClass == FieldReferenceExpression.class) && ((FieldReferenceExpression)expression).getName().startsWith("this$")) { - // Bridge method => Do not bind - bindings = Collections.emptyMap(); - } else { - bindings = new HashMap<>(); - bindings.putAll(contextualBindings); - for (TypeParameter typeParameter : typeParameters) { - bindings.put(typeParameter.getIdentifier(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); - } - } - } else { - bindings = createBindings(typeParameters, typeArguments, methodTypes.typeParameters); + bindings = createBindings(expression, typeParameters, typeArguments, null, PrimitiveType.TYPE_VOID, null, null, null); } + + type = (Type)bindParameterTypesWithArgumentTypes(bindings, type); } } } - - if (!bindings.isEmpty()) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); - returnedType = (Type) bindParameterTypesWithArgumentTypes(objectType, methodTypes.returnedType); - parameterTypes = bindParameterTypesWithArgumentTypes(objectType, methodTypes.parameterTypes); - } - - parameters = prepareParameters(parameters, parameterTypes); } - return new ClassFileMethodInvocationExpression( - this, lineNumber, methodTypes.typeParameters, returnedType, expression, - objectType.getInternalName(), name, descriptor, parameterTypes, parameters); + return new FieldReferenceExpression(lineNumber, type, expression, objectType.getInternalName(), name, descriptor); } - public FieldReferenceExpression newFieldReferenceExpression( - int lineNumber, Type type, Expression expression, ObjectType objectType, String name, String descriptor) { - - if (type.isObject()) { - ObjectType ot = (ObjectType)type; + public void updateNewExpression(ClassFileNewExpression ne, String descriptor, TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { + ne.set(descriptor, clone(methodTypes.parameterTypes), parameters); + } - if (ot.getTypeArguments() != null) { - Map bindings = contextualBindings; + public void bindParameterTypesWithArgumentTypes(Type type, Expression expression) { + bindVisitor.init(type); + expression.accept(bindVisitor); + } - if (expression.getClass() != ThisExpression.class) { - Type expressionType = expression.getType(); + protected Type checkTypeArguments(Type type, AbstractLocalVariable localVariable) { + if (type.isObject()) { + ObjectType objectType = (ObjectType)type; - if (expressionType.isObject()) { - ObjectType expressionObjectType = (ObjectType) expressionType; - TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(expressionObjectType.getInternalName()); + if (objectType.getTypeArguments() != null) { + Type localVariableType = localVariable.getType(); - if (typeTypes != null) { - BaseTypeParameter typeParameters = typeTypes.typeParameters; - BaseTypeArgument typeArguments = expressionObjectType.getTypeArguments(); + if (localVariableType.isObject()) { + ObjectType localVariableObjectType = (ObjectType)localVariableType; + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(localVariableObjectType.getInternalName()); - if ((typeParameters != null) && (typeArguments == null)) { - bindings = new HashMap<>(); - bindings.putAll(contextualBindings); - for (TypeParameter typeParameter : typeParameters) { - bindings.put(typeParameter.getIdentifier(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); - } - } else { - bindings = createBindings(typeParameters, typeArguments, null); - } - } + if ((typeTypes != null) && (typeTypes.typeParameters == null)) { + type = ((ObjectType)type).createType(null); } } - - if (!bindings.isEmpty()) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); - type = (Type) bindParameterTypesWithArgumentTypes(objectType, type); - } } } - return new FieldReferenceExpression(lineNumber, type, expression, objectType.getInternalName(), name, descriptor); + return type; } - public void updateNewExpression(Expression expression, String descriptor, TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { - ClassFileNewExpression ne = (ClassFileNewExpression)expression; - BaseType parameterTypes = methodTypes.parameterTypes; - Map bindings = contextualBindings; + protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileMethodInvocationExpression mie) { + BaseType parameterTypes = mie.getParameterTypes(); + BaseExpression parameters = mie.getParameters(); + Expression expression = mie.getExpression(); + Type expressionType = expression.getType(); + + if (staticMethod || (mie.getTypeParameters() != null) || expressionType.isGeneric() || (expression.getClass() != ThisExpression.class)) { + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(mie.getInternalTypeName()); + + if (typeTypes != null) { + BaseTypeParameter typeParameters = typeTypes.typeParameters; + BaseTypeParameter methodTypeParameters = mie.getTypeParameters(); + BaseTypeArgument typeArguments; + + if (expression.getClass() == SuperExpression.class) { + typeTypes = typeMaker.makeTypeTypes(internalTypeName); + typeArguments = (typeTypes.superType == null) ? null : typeTypes.superType.getTypeArguments(); + } else if (expression.getClass() == ClassFileMethodInvocationExpression.class) { + Type t = getExpressionType((ClassFileMethodInvocationExpression) expression); + if ((t != null) && t.isObject()) { + typeArguments = ((ObjectType)t).getTypeArguments(); + } else { + typeArguments = null; + } + } else if (expressionType.isGeneric()) { + typeArguments = null; + } else { + typeArguments = ((ObjectType)expressionType).getTypeArguments(); + } - if (!ne.getObjectType().getInternalName().equals(internalTypeName)) { - if (parameterTypes != null) { - TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(ne.getObjectType().getInternalName()); + Type t = mie.getType(); - if ((typeTypes != null) && (typeTypes.typeParameters != null)) { - bindings = new HashMap<>(); - bindings.putAll(contextualBindings); + if (type.isObject() && t.isObject()) { + ObjectType objectType = (ObjectType) type; + ObjectType mieTypeObjectType = (ObjectType) t; + t = typeMaker.searchSuperParameterizedType(objectType, mieTypeObjectType); + } - populateBindingsWithTypeParameterVisitor.init(bindings); - typeTypes.typeParameters.accept(populateBindingsWithTypeParameterVisitor); + Map bindings = createBindings(expression, typeParameters, typeArguments, methodTypeParameters, type, t, parameterTypes, parameters); - if (parameterTypes.size() > 1) { - Iterator parametersIterator = parameters.iterator(); - Iterator parameterTypesIterator = parameterTypes.iterator(); + mie.setParameterTypes(parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes)); + mie.setType((Type) bindParameterTypesWithArgumentTypes(bindings, mie.getType())); - while (parametersIterator.hasNext()) { - Expression parameter = parametersIterator.next(); - Type parameterType = parameterTypesIterator.next(); + if (expressionType.isObject()) { + ObjectType expressionObjectType = (ObjectType) expressionType; - if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { - populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); - parameterType.accept(populateBindingsWithTypeArgumentVisitor); + if (bindings.containsValue(null)) { + expressionType = expressionObjectType.createType(null); + } else { + boolean statik = (expression.getClass() == ObjectTypeReferenceExpression.class); + + if (statik || (typeParameters == null)) { + expressionType = expressionObjectType.createType(null); + } else if (typeParameters.isList()) { + TypeArguments tas = new TypeArguments(typeParameters.size()); + for (TypeParameter typeParameter : typeParameters) { + tas.add(bindings.get(typeParameter.getIdentifier())); } - } - } else if (parameterTypes.size() > 0) { - Expression parameter = parameters.getFirst(); - - if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression) parameter).getTypeParameters() == null)) { - populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); - parameterTypes.getFirst().accept(populateBindingsWithTypeArgumentVisitor); + expressionType = expressionObjectType.createType(tas); + } else { + expressionType = expressionObjectType.createType(bindings.get(typeParameters.getFirst().getIdentifier())); } } + } + } + } - if (!bindings.containsValue(null)) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + bindParameterTypesWithArgumentTypes(expressionType, expression); + bindParameterTypesWithArgumentTypes(parameterTypes, parameters); + } - if (typeTypes.typeParameters.isList()) { - TypeArguments tas = new TypeArguments(typeTypes.typeParameters.size()); - boolean object = true; + protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileNewExpression ne) { + BaseType parameterTypes = ne.getParameterTypes(); + BaseExpression parameters = ne.getParameters(); + ObjectType neObjectType = ne.getObjectType(); - for (TypeParameter typeParameter : typeTypes.typeParameters) { - bindTypeParametersToTypeArgumentsVisitor.init(); - new GenericType(typeParameter.getIdentifier()).accept(bindTypeParametersToTypeArgumentsVisitor); - BaseType baseType = bindTypeParametersToTypeArgumentsVisitor.getType(); - object &= TYPE_OBJECT.equals(baseType); - tas.add((Type) baseType); - } + if (staticMethod || !neObjectType.getInternalName().equals(internalTypeName)) { + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(neObjectType.getInternalName()); - if (!object) { - ne.setType(ne.getObjectType().createType(tas)); - } - } else { - bindTypeParametersToTypeArgumentsVisitor.init(); - new GenericType(typeTypes.typeParameters.getFirst().getIdentifier()).accept(bindTypeParametersToTypeArgumentsVisitor); - BaseType baseType = bindTypeParametersToTypeArgumentsVisitor.getType(); + if (typeTypes != null) { + BaseTypeParameter typeParameters = typeTypes.typeParameters; + BaseTypeArgument typeArguments = neObjectType.getTypeArguments(); - if (!TYPE_OBJECT.equals(baseType)) { - ne.setType(ne.getObjectType().createType((Type)baseType)); - } + if ((typeParameters != null) && (typeArguments == null)) { + if (typeParameters.isList()) { + TypeArguments tas = new TypeArguments(typeParameters.size()); + for (TypeParameter typeParameter : typeParameters) { + tas.add(new GenericType(typeParameter.getIdentifier())); } + neObjectType = neObjectType.createType(tas); + } else { + neObjectType = neObjectType.createType(new GenericType(typeParameters.getFirst().getIdentifier())); } } + + Type t = neObjectType; + + if (type.isObject()) { + ObjectType objectType = (ObjectType)type; + t = typeMaker.searchSuperParameterizedType(objectType, neObjectType); + } + + Map bindings = createBindings(null, typeParameters, typeArguments, null, type, t, parameterTypes, parameters); + + ne.setParameterTypes(parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes)); + + // Replace wildcards + for (Map.Entry entry : bindings.entrySet()) { + typeArgumentToTypeVisitor.init(); + entry.getValue().accept(typeArgumentToTypeVisitor); + entry.setValue(typeArgumentToTypeVisitor.getType()); + } + + ne.setType((ObjectType) bindParameterTypesWithArgumentTypes(bindings, neObjectType)); } + } - if (!bindings.isEmpty() && !bindings.containsValue(null)) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); - parameterTypes = bindParameterTypesWithArgumentTypes(ne.getObjectType(), parameterTypes); + bindParameterTypesWithArgumentTypes(parameterTypes, parameters); + } + + protected void bindParameterTypesWithArgumentTypes(BaseType types, BaseExpression expressions) { + if (types != null) { + if (types.isList()) { + Iterator parameterTypesIterator = types.iterator(); + Iterator parametersIterator = expressions.iterator(); + + while (parametersIterator.hasNext()) { + bindParameterTypesWithArgumentTypes(parameterTypesIterator.next(), parametersIterator.next()); + } + } else { + bindParameterTypesWithArgumentTypes(types.getFirst(), expressions.getFirst()); } } + } - parameters = prepareParameters(parameters, parameterTypes); - ((ClassFileNewExpression)expression).set(descriptor, parameterTypes, parameters); + public static void staticBindParameterTypesWithArgumentTypes(Type type, Expression expression) { + if (expression.getClass() == ClassFileMethodInvocationExpression.class) { + ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; + TypeParametersToTypeArgumentsBinder binder = mie.getBinder(); + + if (binder != null) { + binder.bindParameterTypesWithArgumentTypes(type, mie); + } + } } - protected Map createBindings(BaseTypeParameter typeParameters, BaseTypeArgument typeArguments, BaseTypeParameter methodTypeParameters) { - if ((typeParameters == null) && (methodTypeParameters == null)) { - return contextualBindings; - } else { - HashMap bindings = new HashMap<>(); + protected Map createBindings( + Expression expression, + BaseTypeParameter typeParameters, BaseTypeArgument typeArguments, BaseTypeParameter methodTypeParameters, + Type returnType, Type returnExpressionType, BaseType parameterTypes, BaseExpression parameters) { + + Map bindings = new HashMap<>(); + Map typeBounds = new HashMap<>(); + boolean statik = (expression != null) && (expression.getClass() == ObjectTypeReferenceExpression.class); + if (!statik) { bindings.putAll(contextualBindings); - if ((typeParameters != null) && (typeArguments != null)) { - if (typeParameters.isList()) { - Iterator iteratorTypeParameter = typeParameters.iterator(); - Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); + if (typeParameters != null) { + populateBindingsWithTypeParameterVisitor.init(bindings, typeBounds); + typeParameters.accept(populateBindingsWithTypeParameterVisitor); - while (iteratorTypeParameter.hasNext()) { - bindings.put(iteratorTypeParameter.next().getIdentifier(), iteratorTypeArgument.next()); - } - } else { - bindings.put(typeParameters.getFirst().getIdentifier(), typeArguments.getTypeArgumentFirst()); - } - } + if (typeArguments != null) { + if (typeParameters.isList()) { + Iterator iteratorTypeParameter = typeParameters.iterator(); + Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); - if (methodTypeParameters != null) { - if (methodTypeParameters.isList()) { - for (TypeParameter tp : methodTypeParameters) { - String identifier = tp.getIdentifier(); - bindings.put(identifier, new GenericType(identifier)); + while (iteratorTypeParameter.hasNext()) { + bindings.put(iteratorTypeParameter.next().getIdentifier(), iteratorTypeArgument.next()); + } + } else { + bindings.put(typeParameters.getFirst().getIdentifier(), typeArguments.getTypeArgumentFirst()); } - } else { - String identifier = methodTypeParameters.getFirst().getIdentifier(); - bindings.put(identifier, new GenericType(identifier)); } } - - return bindings; } - } - protected BaseType bindParameterTypesWithArgumentTypes(ObjectType objectType, BaseType baseType) { - if (baseType == null) { - return null; + if (methodTypeParameters != null) { + populateBindingsWithTypeParameterVisitor.init(bindings, typeBounds); + methodTypeParameters.accept(populateBindingsWithTypeParameterVisitor); } - if (objectType.getInternalName().equals(internalTypeName)) { - return baseType; + if ((returnType != PrimitiveType.TYPE_VOID) && (returnExpressionType != null)) { + populateBindingsWithTypeArgumentVisitor.init(contextualTypeBounds, bindings, typeBounds, returnType); + returnExpressionType.accept(populateBindingsWithTypeArgumentVisitor); } - bindTypeParametersToTypeArgumentsVisitor.init(); - baseType.accept(bindTypeParametersToTypeArgumentsVisitor); + if (parameterTypes != null) { + if (parameterTypes.isList()) { + Iterator parameterTypesIterator = parameterTypes.iterator(); + Iterator parametersIterator = parameters.iterator(); - return bindTypeParametersToTypeArgumentsVisitor.getType(); - } + while (parametersIterator.hasNext()) { + populateBindingsWithTypeArgument(bindings, typeBounds, parameterTypesIterator.next(), parametersIterator.next()); + } + } else { + populateBindingsWithTypeArgument(bindings, typeBounds, parameterTypes.getFirst(), parameters.getFirst()); + } + } - @SuppressWarnings("unchecked") - protected BaseExpression prepareParameters(BaseExpression parameterExpressions, BaseType parameterTypes) { - if (parameterTypes != null) { - int size = parameterTypes.size(); + if (bindings.containsValue(null)) { + if (eraseTypeArguments(expression, typeParameters, typeArguments)) { + for (Map.Entry entry : bindings.entrySet()) { + entry.setValue(null); + } + } else { + for (Map.Entry entry : bindings.entrySet()) { + if (entry.getValue() == null) { + BaseType baseType = typeBounds.get(entry.getKey()); - if (size == 1) { - Expression parameter = parameterExpressions.getFirst(); - Type type = parameterTypes.getFirst(); + if (baseType == null) { + entry.setValue(WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } else { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + bindTypeParametersToTypeArgumentsVisitor.init(); + baseType.accept(bindTypeParametersToTypeArgumentsVisitor); + baseType = bindTypeParametersToTypeArgumentsVisitor.getType(); - if (parameter.getClass() == ClassFileLocalVariableReferenceExpression.class) { - AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) parameter).getLocalVariable(); - localVariable.typeOnLeft(checkTypeArguments(type, localVariable)); + baseTypeToTypeArgumentVisitor.init(); + baseType.accept(baseTypeToTypeArgumentVisitor); + entry.setValue(baseTypeToTypeArgumentVisitor.getTypeArgument()); + } + } } + } + } - bindParameterTypesWithArgumentTypes(type, parameter); - } else if (size > 1) { - DefaultList parameters = parameterExpressions.getList(); - DefaultList types = parameterTypes.getList(); + return bindings; + } - for (int i=0; i bindings, Map typeBounds, Type type, Expression expression) { + Type t = getExpressionType(expression); - if (objectType.getTypeArguments() != null) { - Type localVariableType = localVariable.getType(); + if (t != null) { + populateBindingsWithTypeArgumentVisitor.init(contextualTypeBounds, bindings, typeBounds, t); + type.accept(populateBindingsWithTypeArgumentVisitor); + } + } - if (localVariableType.isObject()) { - ObjectType localVariableObjectType = (ObjectType)localVariableType; - TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(localVariableObjectType.getInternalName()); + protected BaseType bindParameterTypesWithArgumentTypes(Map bindings, BaseType parameterTypes) { + if ((parameterTypes != null) && !bindings.isEmpty()) { + bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + bindTypeParametersToTypeArgumentsVisitor.init(); + parameterTypes.accept(bindTypeParametersToTypeArgumentsVisitor); + parameterTypes = bindTypeParametersToTypeArgumentsVisitor.getType(); + } - if ((typeTypes != null) && (typeTypes.typeParameters == null)) { - type = ((ObjectType)type).createType(null); - } - } + return parameterTypes; + } + + protected BaseType clone(BaseType parameterTypes) { + if ((parameterTypes != null) && parameterTypes.isList()) { + switch (parameterTypes.size()) { + case 0: + parameterTypes = null; + break; + case 1: + parameterTypes = parameterTypes.getFirst(); + break; + default: + parameterTypes = new Types(parameterTypes.getList()); + break; } } - return type; + return parameterTypes; } - public void bindParameterTypesWithArgumentTypes(Type type, Expression expression) { + protected Type getExpressionType(Expression expression) { Class expressionClass = expression.getClass(); if (expressionClass == ClassFileMethodInvocationExpression.class) { - ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; - - if (mie.getTypeParameters() != null) { - bindParameterTypesWithArgumentTypes(type, mie); - } + return getExpressionType((ClassFileMethodInvocationExpression)expression); } else if (expressionClass == ClassFileNewExpression.class) { - if (contextualBindings != null) { - ClassFileNewExpression ne = (ClassFileNewExpression) expression; - - if (ne.getParameterTypes() != null) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(contextualBindings); - - bindTypeParametersToTypeArgumentsVisitor.init(); - ne.getParameterTypes().accept(bindTypeParametersToTypeArgumentsVisitor); - ne.setParameterTypes(bindTypeParametersToTypeArgumentsVisitor.getType()); - } - } + return getExpressionType((ClassFileNewExpression)expression); } + + return expression.getType(); } - protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileMethodInvocationExpression mie) { - HashMap bindings = new HashMap<>(); + protected Type getExpressionType(ClassFileMethodInvocationExpression mie) { + Type t = mie.getType(); - if (mie.getExpression().getClass() != ObjectTypeReferenceExpression.class) { - // Non-static method invocation - bindings.putAll(contextualBindings); + searchInTypeArgumentVisitor.init(); + t.accept(searchInTypeArgumentVisitor); + + if (!searchInTypeArgumentVisitor.containsGeneric()) { + return t; } if (mie.getTypeParameters() != null) { - populateBindingsWithTypeParameterVisitor.init(bindings); - mie.getTypeParameters().accept(populateBindingsWithTypeParameterVisitor); + return null; } - if (type != PrimitiveType.TYPE_VOID) { - populateBindingsWithTypeArgumentVisitor.init(bindings, type); - mie.getType().accept(populateBindingsWithTypeArgumentVisitor); + if (staticMethod || (mie.getExpression().getClass() != ThisExpression.class)) { + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(mie.getInternalTypeName()); + + if ((typeTypes != null) && (typeTypes.typeParameters != null)) { + return null; + } } - if (mie.getParameterTypes() != null) { - BaseType parameterTypes = mie.getParameterTypes(); + return t; + } - if (parameterTypes.size() > 1) { - Iterator parametersIterator = mie.getParameters().iterator(); - Iterator parameterTypesIterator = mie.getParameterTypes().iterator(); + protected Type getExpressionType(ClassFileNewExpression ne) { + ObjectType ot = ne.getObjectType(); - while (parametersIterator.hasNext()) { - Expression parameter = parametersIterator.next(); - Type parameterType = parameterTypesIterator.next(); + if (staticMethod || !ot.getInternalName().equals(internalTypeName)) { + TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(ot.getInternalName()); - if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression)parameter).getTypeParameters() == null)) { - populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); - parameterType.accept(populateBindingsWithTypeArgumentVisitor); - } - } - } else if (parameterTypes.size() > 0) { - Expression parameter = mie.getParameters().getFirst(); + if ((typeTypes != null) && (typeTypes.typeParameters != null)) { + return null; + } + } - if ((parameter.getClass() != ClassFileMethodInvocationExpression.class) || (((ClassFileMethodInvocationExpression)parameter).getTypeParameters() == null)) { - populateBindingsWithTypeArgumentVisitor.init(bindings, parameter.getType()); - parameterTypes.getFirst().accept(populateBindingsWithTypeArgumentVisitor); - } + return ot; + } + + protected class BindVisitor extends AbstractNopExpressionVisitor { + protected Type type; + + public void init(Type type) { + this.type = type; + } + + @Override + public void visit(MethodInvocationExpression expression) { + ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; + bindParameterTypesWithArgumentTypes(type, mie); + } + + @Override + public void visit(LocalVariableReferenceExpression expression) { + if (!type.isPrimitive()) { + AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); + localVariable.typeOnLeft(checkTypeArguments(type, localVariable)); } } - assert !bindings.isEmpty() : "TypeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(...): Bindings is empty"; + @Override + public void visit(NewExpression expression) { + ClassFileNewExpression ne = (ClassFileNewExpression)expression; + bindParameterTypesWithArgumentTypes(type, ne); + } - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + @Override + public void visit(CastExpression expression) { + assert (type.getDimension() == expression.getType().getDimension()) : "TypeParametersToTypeArgumentsBinder.visit(CastExpression ce) : invalid array type"; - bindTypeParametersToTypeArgumentsVisitor.init(); - mie.getType().accept(bindTypeParametersToTypeArgumentsVisitor); - mie.setType((Type) bindTypeParametersToTypeArgumentsVisitor.getType()); + if (type.isObject()) { + ObjectType objectType = (ObjectType)type; - if (mie.getParameterTypes() != null) { - bindTypeParametersToTypeArgumentsVisitor.init(); - mie.getParameterTypes().accept(bindTypeParametersToTypeArgumentsVisitor); - mie.setParameterTypes(bindTypeParametersToTypeArgumentsVisitor.getType()); + if ((objectType.getTypeArguments() != null) && !objectType.getTypeArguments().equals(WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT)) { + assert expression.getType().isObject() : "TypeParametersToTypeArgumentsBinder.visit(CastExpression ce) : invalid object type"; - BaseType parameterTypes = mie.getParameterTypes(); + ObjectType expressionObjectType = (ObjectType) expression.getType(); - if (parameterTypes.size() > 1) { - Iterator parametersIterator = mie.getParameters().iterator(); - Iterator parameterTypesIterator = mie.getParameterTypes().iterator(); + if (objectType.getInternalName().equals(expressionObjectType.getInternalName())) { + Type expressionExpressionType = expression.getExpression().getType(); - while (parametersIterator.hasNext()) { - bindParameterTypesWithArgumentTypes(parameterTypesIterator.next(), parametersIterator.next()); + if (expressionExpressionType.isObject()) { + ObjectType expressionExpressionObjectType = (ObjectType)expressionExpressionType; + + if (expressionExpressionObjectType.getTypeArguments() == null) { + expression.setType(objectType); + } else if (objectType.getTypeArguments().isTypeArgumentAssignableFrom(expressionExpressionObjectType.getTypeArguments())) { + expression.setType(objectType); + } + } else if (expressionExpressionType.isGeneric()) { + expression.setType(objectType); + } + } } - } else if (parameterTypes.size() > 0) { - bindParameterTypesWithArgumentTypes(parameterTypes.getFirst(), mie.getParameters().getFirst()); } - } - bindParameterTypesWithArgumentTypes(mie.getType(), mie.getExpression()); - } + type = expression.getType(); + expression.getExpression().accept(this); + } - public static void staticBindParameterTypesWithArgumentTypes(Type type, Expression expression) { - if (expression.getClass() == ClassFileMethodInvocationExpression.class) { - ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; - TypeParametersToTypeArgumentsBinder binder = mie.getBinder(); + @Override + public void visit(TernaryOperatorExpression expression) { + expression.setType(type); + bindParameterTypesWithArgumentTypes(type, expression.getExpressionTrue()); + bindParameterTypesWithArgumentTypes(type, expression.getExpressionFalse()); + } - if (binder != null) { - binder.bindParameterTypesWithArgumentTypes(type, mie); - } + @Override + public void visit(BinaryOperatorExpression expression) { + bindParameterTypesWithArgumentTypes(type, expression.getLeftExpression()); + bindParameterTypesWithArgumentTypes(type, expression.getRightExpression()); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/WatchDog.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/WatchDog.java index 04c5704c..3cec25bf 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/WatchDog.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/WatchDog.java @@ -41,7 +41,7 @@ public Link(BasicBlock parent, BasicBlock child) { @Override public int hashCode() { - return parentIndex + 31 * childIndex; + return 4807589 + parentIndex + 31 * childIndex; } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index e67b3a4e..f4778cdf 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -18,15 +18,12 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.util.DefaultList; -import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; public class AddCastExpressionVisitor extends AbstractJavaSyntaxVisitor { - protected TypeMaker typeMaker; protected Type returnedType; protected Type type; - protected int extraDimension = 0; public AddCastExpressionVisitor(TypeMaker typeMaker) { this.typeMaker = typeMaker; @@ -46,11 +43,17 @@ public void visit(FieldDeclarator declarator) { VariableInitializer variableInitializer = declarator.getVariableInitializer(); if (variableInitializer != null) { - int d = extraDimension; + int extraDimension = declarator.getDimension(); + + if (extraDimension == 0) { + variableInitializer.accept(this); + } else { + Type t = type; - extraDimension = declarator.getDimension(); - variableInitializer.accept(this); - extraDimension = d; + type = type.createType(type.getDimension() + extraDimension); + variableInitializer.accept(this); + type = t; + } } } @@ -103,40 +106,38 @@ public void visit(LocalVariableDeclarator declarator) { VariableInitializer variableInitializer = declarator.getVariableInitializer(); if (variableInitializer != null) { - int d = extraDimension; + int extraDimension = declarator.getDimension(); + + if (extraDimension == 0) { + variableInitializer.accept(this); + } else { + Type t = type; - extraDimension = declarator.getDimension(); - variableInitializer.accept(this); - extraDimension = d; + type = type.createType(type.getDimension() + extraDimension); + variableInitializer.accept(this); + type = t; + } } } @Override - public void visit(ExpressionVariableInitializer declaration) { - Expression expression = declaration.getExpression(); + public void visit(ArrayVariableInitializer declaration) { + Type t = type; - if (expression.getClass() == ClassFileMethodInvocationExpression.class) { - ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; + type = type.createType(type.getDimension() - 1); + acceptListDeclaration(declaration); + type = t; + } - if (mie.getTypeParameters() != null) { - // Do nor add cast expression if method contains type parameters - expression.accept(this); - return; - } - } + @Override + public void visit(ExpressionVariableInitializer declaration) { + Expression expression = declaration.getExpression(); if (expression.getClass() == NewInitializedArray.class) { ((NewInitializedArray)expression).getArrayInitializer().accept(this); - return; - } - - Type t = type; - - if (extraDimension > 0) { - t = t.createType(t.getDimension() + extraDimension); + } else { + declaration.setExpression(updateExpression(type, expression)); } - - declaration.setExpression(updateExpression(t, expression)); } @Override @@ -188,7 +189,6 @@ public void visit(NewInitializedArray expression) { Type t = type; type = expression.getType(); - type = type.createType(type.getDimension() - 1); arrayInitializer.accept(this); type = t; } @@ -218,6 +218,16 @@ public void visit(BinaryOperatorExpression expression) { rightExpression.accept(this); } + @Override + public void visit(TernaryOperatorExpression expression) { + Type expressionType = expression.getType(); + + expression.getCondition().accept(this); + + expression.setExpressionTrue(updateExpression(expressionType, expression.getExpressionTrue())); + expression.setExpressionFalse(updateExpression(expressionType, expression.getExpressionFalse())); + } + @SuppressWarnings("unchecked") protected BaseExpression updateExpressions(BaseType types, BaseExpression expressions) { if (expressions != null) { @@ -245,21 +255,20 @@ private Expression updateExpression(Type type, Expression expression) { if (expressionType.isObject()) { ObjectType objectType = (ObjectType) type; ObjectType expressionObjectType = (ObjectType) expressionType; - String internalName = objectType.getInternalName(); - - if (internalName.equals(expressionObjectType.getInternalName()) || typeMaker.isAssignable(objectType, expressionObjectType)) { - if (expressionObjectType.getTypeArguments() == null) { - if (objectType.getTypeArguments() != null) { - expression = addCastExpression(type, expression); - } - } else { - if (objectType.getTypeArguments() == null) { - expression = addCastExpression(type, expression); - } else if (!objectType.getTypeArguments().isTypeArgumentAssignableFrom(expressionObjectType.getTypeArguments())) { - expression = addCastExpression(objectType.createType(null), expression); - } + + if (!typeMaker.isAssignable(objectType, expressionObjectType)) { + BaseTypeArgument ta1 = objectType.getTypeArguments(); + BaseTypeArgument ta2 = expressionObjectType.getTypeArguments(); + Type t = type; + + if ((ta1 != null) && (ta2 != null) && !ta1.isTypeArgumentAssignableFrom(ta2)) { + // Incompatible typeArgument arguments => Uses raw typeArgument + t = objectType.createType(null); } + expression = addCastExpression(t, expression); } + } else if (expressionType.isGeneric()) { + expression = addCastExpression(type, expression); } } else if (type.isGeneric()) { if (expressionType.isObject() || expressionType.isGeneric()) { @@ -269,6 +278,16 @@ private Expression updateExpression(Type type, Expression expression) { } } + if (expression.getClass() == CastExpression.class) { + CastExpression ce = (CastExpression)expression; + Type ceExpressionType = ce.getExpression().getType(); + + if (type.isObject() && ceExpressionType.isObject() && typeMaker.isAssignable((ObjectType)type, (ObjectType)ceExpressionType)) { + // Remove cast expression + expression = ce.getExpression(); + } + } + expression.accept(this); return expression; @@ -282,27 +301,18 @@ private static final boolean match(Expression expression) { return false; } - if (expressionClass == ClassFileMethodInvocationExpression.class) { - ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; - - if (mie.getTypeParameters() != null) { - // Do not add a cast before parameterized method invocation - return false; - } - } - return true; } private static final Expression addCastExpression(Type type, Expression expression) { if (expression.getClass() == CastExpression.class) { - CastExpression ca = (CastExpression)expression; + CastExpression ce = (CastExpression)expression; - if (type.equals(ca.getExpression().getType())) { - return ca.getExpression(); + if (type.equals(ce.getExpression().getType())) { + return ce.getExpression(); } else { - ca.setType(type); - return ca; + ce.setType(type); + return ce; } } else { return new CastExpression(expression.getLineNumber(), type, expression); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java new file mode 100644 index 00000000..1db0d389 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; + +public class BaseTypeToErasedTypeArgumentVisitor implements TypeVisitor { + protected TypeArgument typeArgument; + + public void init() { + this.typeArgument = null; + } + + public TypeArgument getTypeArgument() { + return typeArgument; + } + + @Override public void visit(PrimitiveType type) { typeArgument = type; } + @Override public void visit(ObjectType type) { typeArgument = type.createType(null); } + @Override public void visit(InnerObjectType type) { typeArgument = type.createType(null); } + @Override public void visit(GenericType type) { typeArgument = TYPE_OBJECT; } + + @Override + public void visit(Types types) { + if (types.isEmpty()) { + typeArgument = WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; + } else { + types.getFirst().accept(this); + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToTypeArgumentVisitor.java new file mode 100644 index 00000000..cd07e471 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToTypeArgumentVisitor.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import java.util.Map; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; + +public class BaseTypeToTypeArgumentVisitor implements TypeVisitor { + protected TypeArgument typeArgument; + + public void init() { + this.typeArgument = null; + } + + public TypeArgument getTypeArgument() { + return typeArgument; + } + + @Override public void visit(PrimitiveType type) { typeArgument = type; } + @Override public void visit(ObjectType type) { typeArgument = type; } + @Override public void visit(InnerObjectType type) { typeArgument = type; } + @Override public void visit(GenericType type) { typeArgument = type; } + + @Override + public void visit(Types types) { + if (types.isEmpty()) { + typeArgument = WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; + } else { + types.getFirst().accept(this); + } + } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java new file mode 100644 index 00000000..46056980 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import java.util.Map; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; + +public class BindTypeArgumentsToTypeArgumentsVisitor extends AbstractTypeArgumentVisitor { + protected TypeArgumentToTypeVisitor typeArgumentToTypeVisitor = new TypeArgumentToTypeVisitor(); + protected Map bindings; + protected BaseTypeArgument result; + + public void setBindings(Map bindings) { + this.bindings = bindings; + } + + public void init() { + this.result = null; + } + + public BaseTypeArgument getTypeArgument() { + if ((result == null) || TYPE_OBJECT.equals(result)) { + return null; + } + return result; + } + + @Override + public void visit(TypeArguments arguments) { + int size = arguments.size(); + int i; + + for (i=0; i bindings; protected BaseType result; public void setBindings(Map bindings) { - bindTypeArgumentVisitor.setBindings(this.bindings = bindings); + bindTypeArgumentsToTypeArgumentsVisitor.setBindings(this.bindings = bindings); } public void init() { @@ -44,14 +44,12 @@ public void visit(ObjectType type) { if (typeArguments == null) { result = type; } else { - bindTypeArgumentVisitor.init(); - typeArguments.accept(bindTypeArgumentVisitor); - BaseTypeArgument ta = bindTypeArgumentVisitor.getTypeArgument(); + bindTypeArgumentsToTypeArgumentsVisitor.init(); + typeArguments.accept(bindTypeArgumentsToTypeArgumentsVisitor); + BaseTypeArgument ta = bindTypeArgumentsToTypeArgumentsVisitor.getTypeArgument(); if (typeArguments == ta) { result = type; - } else if (WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT == ta) { - result = type.createType(null); } else { result = type.createType(ta); } @@ -68,14 +66,12 @@ public void visit(InnerObjectType type) { if (typeArguments == null) { result = type; } else { - bindTypeArgumentVisitor.init(); - typeArguments.accept(bindTypeArgumentVisitor); - BaseTypeArgument ta = bindTypeArgumentVisitor.getTypeArgument(); + bindTypeArgumentsToTypeArgumentsVisitor.init(); + typeArguments.accept(bindTypeArgumentsToTypeArgumentsVisitor); + BaseTypeArgument ta = bindTypeArgumentsToTypeArgumentsVisitor.getTypeArgument(); if (typeArguments == ta) { result = type; - } else if (WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT == ta) { - result = type.createType(null); } else { result = type.createType(ta); } @@ -84,9 +80,9 @@ public void visit(InnerObjectType type) { ObjectType outerObjectType = (ObjectType) result; if (typeArguments != null) { - bindTypeArgumentVisitor.init(); - typeArguments.accept(bindTypeArgumentVisitor); - typeArguments = bindTypeArgumentVisitor.getTypeArgument(); + bindTypeArgumentsToTypeArgumentsVisitor.init(); + typeArguments.accept(bindTypeArgumentsToTypeArgumentsVisitor); + typeArguments = bindTypeArgumentsToTypeArgumentsVisitor.getTypeArgument(); if (WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT == typeArguments) { typeArguments = null; @@ -142,178 +138,4 @@ public void visit(Types types) { result = newTypes; } } - - protected class BindTypeArgumentVisitor extends AbstractTypeArgumentVisitor { - protected Map bindings; - protected BaseTypeArgument result; - - public void setBindings(Map bindings) { - this.bindings = bindings; - } - - public void init() { - this.result = null; - } - - public BaseTypeArgument getTypeArgument() { - if ((result == null) || TYPE_OBJECT.equals(result)) { - return null; - } - - return result; - } - - @Override - public void visit(TypeArguments arguments) { - int size = arguments.size(); - int i; - - for (i=0; i syntheticInnerFieldNames = new DefaultList<>(); - protected Map> syntheticInnerFieldNameToSyntheticInnerFieldReferences = new HashMap<>(); protected ObjectType outerType; @Override @@ -63,7 +62,6 @@ public void visit(BodyDeclaration declaration) { // Init attributes outerType = null; syntheticInnerFieldNames.clear(); - syntheticInnerFieldNameToSyntheticInnerFieldReferences.clear(); // Visit methods safeAcceptListDeclaration(bodyDeclaration.getMethodDeclarations()); // Init values @@ -76,10 +74,6 @@ public void visit(BodyDeclaration declaration) { if ((outerType != null) || !syntheticInnerFieldNames.isEmpty()) { updateFieldReferencesVisitor.visit(bodyDeclaration); } - - if (!syntheticInnerFieldNameToSyntheticInnerFieldReferences.isEmpty()) { - bodyDeclaration.setSyntheticInnerFieldNameToSyntheticInnerFieldReferences(new HashMap<>(syntheticInnerFieldNameToSyntheticInnerFieldReferences)); - } } @Override @@ -90,7 +84,6 @@ public void visit(ConstructorDeclaration declaration) { ClassFile outerClassFile = classFile.getOuterClassFile(); syntheticInnerFieldNames.clear(); - syntheticInnerFieldNameToSyntheticInnerFieldReferences.clear(); // Search synthetic field initialization if (cfcd.getStatements().isList()) { @@ -128,7 +121,6 @@ public void visit(ConstructorDeclaration declaration) { outerType = (ObjectType) boe.getRightExpression().getType(); } else if (name.startsWith("val$")) { syntheticInnerFieldNames.add(name); - syntheticInnerFieldNameToSyntheticInnerFieldReferences.put(name, new ArrayList<>()); } } } @@ -227,7 +219,7 @@ public void visit(FieldReferenceExpression expression) { if (expression.getName().startsWith("this$")) { if (expression.getType().getDescriptor().equals(outerType.getDescriptor())) { Expression exp = (expression.getExpression() == null) ? expression : expression.getExpression(); - expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), outerType)); + expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), outerType.createType(null))); expression.setName("this"); } else { ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(expression.getInternalTypeName()); @@ -242,14 +234,15 @@ public void visit(FieldReferenceExpression expression) { if (outerInternalTypeName.equals(objectType.getInternalName())) { Expression exp = (expression.getExpression() == null) ? expression : expression.getExpression(); - expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), objectType)); + expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), objectType.createType(null))); expression.setName("this"); } } } } - } else if (syntheticInnerFieldNameToSyntheticInnerFieldReferences.containsKey(expression.getName())) { - syntheticInnerFieldNameToSyntheticInnerFieldReferences.get(expression.getName()).add(expression); + } else if (expression.getName().startsWith("val$")) { + expression.setName(expression.getName().substring(4)); + expression.setExpression(null); } else { super.visit(expression); } @@ -261,7 +254,7 @@ protected Expression updateExpression(Expression expression) { ClassFileLocalVariableReferenceExpression cdlvre = (ClassFileLocalVariableReferenceExpression) expression; if ((cdlvre.getName() != null) && cdlvre.getName().startsWith("this$") && cdlvre.getType().getDescriptor().equals(outerType.getDescriptor())) { - return new FieldReferenceExpression(outerType, new ObjectTypeReferenceExpression(cdlvre.getLineNumber(), outerType), outerType.getInternalName(), "this", outerType.getDescriptor()); + return new FieldReferenceExpression(outerType, new ObjectTypeReferenceExpression(cdlvre.getLineNumber(), outerType.createType(null)), outerType.getInternalName(), "this", outerType.getDescriptor()); } } @@ -273,7 +266,7 @@ public static class UpdateNewExpressionVisitor extends AbstractJavaSyntaxVisitor protected TypeMaker typeMaker; protected ClassFileBodyDeclaration bodyDeclaration; protected ClassFile classFile; - protected HashSet finalLocalVariableNameSet = new HashSet<>(); + protected HashMap finalLocalVariableNameMap = new HashMap<>(); protected DefaultList localClassDeclarations = new DefaultList<>(); protected HashSet newExpressions = new HashSet<>(); protected int lineNumber; @@ -291,13 +284,13 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(ConstructorDeclaration declaration) { classFile = ((ClassFileConstructorDeclaration)declaration).getClassFile(); - finalLocalVariableNameSet.clear(); + finalLocalVariableNameMap.clear(); localClassDeclarations.clear(); safeAccept(declaration.getStatements()); - if (! finalLocalVariableNameSet.isEmpty()) { - UpdateFinalFieldReferenceVisitor visitor = new UpdateFinalFieldReferenceVisitor(); + if (! finalLocalVariableNameMap.isEmpty()) { + UpdateParametersAndLocalVariablesVisitor visitor = new UpdateParametersAndLocalVariablesVisitor(); declaration.getStatements().accept(visitor); @@ -314,12 +307,12 @@ public void visit(ConstructorDeclaration declaration) { @Override public void visit(MethodDeclaration declaration) { - finalLocalVariableNameSet.clear(); + finalLocalVariableNameMap.clear(); localClassDeclarations.clear(); safeAccept(declaration.getStatements()); - if (! finalLocalVariableNameSet.isEmpty()) { - UpdateFinalFieldReferenceVisitor visitor = new UpdateFinalFieldReferenceVisitor(); + if (! finalLocalVariableNameMap.isEmpty()) { + UpdateParametersAndLocalVariablesVisitor visitor = new UpdateParametersAndLocalVariablesVisitor(); declaration.getStatements().accept(visitor); @@ -336,12 +329,12 @@ public void visit(MethodDeclaration declaration) { @Override public void visit(StaticInitializerDeclaration declaration) { - finalLocalVariableNameSet.clear(); + finalLocalVariableNameMap.clear(); localClassDeclarations.clear(); safeAccept(declaration.getStatements()); - if (! finalLocalVariableNameSet.isEmpty()) { - declaration.getStatements().accept(new UpdateFinalFieldReferenceVisitor()); + if (! finalLocalVariableNameMap.isEmpty()) { + declaration.getStatements().accept(new UpdateParametersAndLocalVariablesVisitor()); } if (! localClassDeclarations.isEmpty()) { @@ -381,10 +374,11 @@ public void visit(NewExpression expression) { if (!newExpressions.contains(expression)) { newExpressions.add(expression); + ClassFileNewExpression ne = (ClassFileNewExpression)expression; ClassFileBodyDeclaration cfbd = null; - if (expression.getBodyDeclaration() == null) { - ObjectType type = expression.getObjectType(); + if (ne.getBodyDeclaration() == null) { + ObjectType type = ne.getObjectType(); String internalName = type.getInternalName(); ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); @@ -397,29 +391,30 @@ public void visit(NewExpression expression) { cfcd.setFlags(cfcd.getFlags() & (~Declaration.FLAG_SYNTHETIC)); localClassDeclarations.add(cfcd); bodyDeclaration.removeInnerType(internalName); - lineNumber = expression.getLineNumber(); + lineNumber = ne.getLineNumber(); } } } else { // Anonymous class - cfbd = (ClassFileBodyDeclaration) expression.getBodyDeclaration(); + cfbd = (ClassFileBodyDeclaration) ne.getBodyDeclaration(); } if (cfbd != null) { - BaseExpression parameters = expression.getParameters(); + BaseExpression parameters = ne.getParameters(); + BaseType parameterTypes = ne.getParameterTypes(); if (parameters != null) { // Remove synthetic parameterTypes DefaultList syntheticInnerFieldNames = cfbd.getSyntheticInnerFieldNames(); - Map> syntheticInnerFieldNameToSyntheticInnerFieldReferences = - cfbd.getSyntheticInnerFieldNameToSyntheticInnerFieldReferences(); if (parameters.isList()) { DefaultList list = parameters.getList(); + DefaultList types = parameterTypes.getList(); if (cfbd.getOuterType() != null) { // Remove outer this - list.remove(0); + list.removeFirst(); + types.removeFirst(); } if (syntheticInnerFieldNames != null) { @@ -440,22 +435,21 @@ public void visit(NewExpression expression) { if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable lv = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable(); - String localVariableName = lv.getName(); - finalLocalVariableNameSet.add(localVariableName); - updateSyntheticInnerFieldReferences( - localVariableName, lv.getType(), syntheticInnerFieldNameToSyntheticInnerFieldReferences.get(syntheticInnerFieldName)); + String localVariableName = syntheticInnerFieldName.substring(4); + finalLocalVariableNameMap.put(lv.getName(), localVariableName); } } lastParameters.clear(); + types.subList(size - count, size).clear(); } } else if (cfbd.getOuterType() != null) { // Remove outer this - expression.setParameters(null); + ne.setParameters(null); + ne.setParameterTypes(null); } else if (syntheticInnerFieldNames != null) { // Remove outer local variable reference Expression param = parameters.getFirst(); - String syntheticInnerFieldName = syntheticInnerFieldNames.getFirst(); if (param.getClass() == CastExpression.class) { param = ((CastExpression) param).getExpression(); @@ -463,26 +457,27 @@ public void visit(NewExpression expression) { if (param.getClass() == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable lv = ((ClassFileLocalVariableReferenceExpression) param).getLocalVariable(); - String localVariableName = lv.getName(); - finalLocalVariableNameSet.add(localVariableName); - updateSyntheticInnerFieldReferences( - localVariableName, lv.getType(), syntheticInnerFieldNameToSyntheticInnerFieldReferences.get(syntheticInnerFieldName)); - expression.setParameters(null); + String localVariableName = syntheticInnerFieldNames.getFirst().substring(4); + finalLocalVariableNameMap.put(lv.getName(), localVariableName); + ne.setParameters(null); + ne.setParameterTypes(null); } } // Is the last parameter synthetic ? - parameters = expression.getParameters(); + parameters = ne.getParameters(); if ((parameters != null) && (parameters.size() > 0) && (parameters.getLast().getClass() == NullExpression.class)) { - BaseType parameterTypes = ((ClassFileNewExpression) expression).getParameterTypes(); + parameterTypes = ne.getParameterTypes(); if (parameterTypes.getLast().getName() == null) { // Yes. Remove it. if (parameters.isList()) { parameters.getList().removeLast(); + parameterTypes.getList().removeLast(); } else { - expression.setParameters(null); + ne.setParameters(null); + ne.setParameterTypes(null); } } } @@ -493,17 +488,10 @@ public void visit(NewExpression expression) { safeAccept(expression.getParameters()); } - protected void updateSyntheticInnerFieldReferences(String name, Type type, List references) { - for (FieldReferenceExpression reference : references) { - reference.setName(name); - reference.setType(type); - reference.setExpression(null); - } - } - @Override public void visit(SuperConstructorInvocationExpression expression) { - BaseExpression parameters = expression.getParameters(); + ClassFileSuperConstructorInvocationExpression scie = (ClassFileSuperConstructorInvocationExpression)expression; + BaseExpression parameters = scie.getParameters(); if ((parameters != null) && (parameters.size() > 0)) { // Remove outer 'this' reference parameter @@ -513,38 +501,36 @@ public void visit(SuperConstructorInvocationExpression expression) { TypeMaker.TypeTypes superTypeTypes = typeMaker.makeTypeTypes(classFile.getSuperTypeName()); if ((superTypeTypes != null) && (superTypeTypes.thisType.getClass() == InnerObjectType.class)) { - if (typeMaker.isAssignable(((InnerObjectType)superTypeTypes.thisType).getOuterType(), (ObjectType)firstParameterType)) { - expression.setParameters(removeOuterThisParameter(parameters)); + if (typeMaker.isRawTypeAssignable(((InnerObjectType)superTypeTypes.thisType).getOuterType(), (ObjectType)firstParameterType)) { + scie.setParameters(removeFirstItem(parameters)); + scie.setParameterTypes(removeFirstItem(scie.getParameterTypes())); } } } // Remove last synthetic parameter - expression.setParameters(removeLastSyntheticParameter( - expression.getParameters(), - ((ClassFileSuperConstructorInvocationExpression)expression).getParameterTypes())); + expression.setParameters(removeLastSyntheticParameter(scie.getParameters(), scie.getParameterTypes())); } } @Override public void visit(ConstructorInvocationExpression expression) { - BaseExpression parameters = expression.getParameters(); + ClassFileConstructorInvocationExpression cie = (ClassFileConstructorInvocationExpression)expression; + BaseExpression parameters = cie.getParameters(); if ((parameters != null) && (parameters.size() > 0)) { // Remove outer this reference parameter if (parameters.getFirst().getType().equals(bodyDeclaration.getOuterType())) { - expression.setParameters(removeOuterThisParameter(parameters)); + cie.setParameters(removeFirstItem(parameters)); + cie.setParameterTypes(removeFirstItem(cie.getParameterTypes())); } // Remove last synthetic parameter - expression.setParameters(removeLastSyntheticParameter( - expression.getParameters(), - ((ClassFileConstructorInvocationExpression)expression).getParameterTypes())); + cie.setParameters(removeLastSyntheticParameter(cie.getParameters(), cie.getParameterTypes())); } } - protected BaseExpression removeOuterThisParameter(BaseExpression parameters) { - // Remove outer 'this' reference parameter + protected BaseExpression removeFirstItem(BaseExpression parameters) { if (parameters.isList()) { parameters.getList().removeFirst(); } else { @@ -554,6 +540,16 @@ protected BaseExpression removeOuterThisParameter(BaseExpression parameters) { return parameters; } + protected BaseType removeFirstItem(BaseType types) { + if (types.isList()) { + types.getList().removeFirst(); + } else { + types = null; + } + + return types; + } + protected BaseExpression removeLastSyntheticParameter(BaseExpression parameters, BaseType parameterTypes) { // Is the last parameter synthetic ? if ((parameters != null) && (parameters.size() > 0) && (parameters.getLast().getClass() == NullExpression.class)) { @@ -570,14 +566,14 @@ protected BaseExpression removeLastSyntheticParameter(BaseExpression parameters, return parameters; } - protected class UpdateFinalFieldReferenceVisitor extends AbstractJavaSyntaxVisitor { + protected class UpdateParametersAndLocalVariablesVisitor extends AbstractJavaSyntaxVisitor { protected boolean fina1; @Override public void visit(FormalParameter declaration) { - if (finalLocalVariableNameSet.contains(declaration.getName())) { + if (finalLocalVariableNameMap.containsKey(declaration.getName())) { declaration.setFinal(true); - declaration.setName(declaration.getName()); + declaration.setName(finalLocalVariableNameMap.get(declaration.getName())); } } @@ -585,25 +581,21 @@ public void visit(FormalParameter declaration) { public void visit(LocalVariableDeclarationStatement statement) { fina1 = false; statement.getLocalVariableDeclarators().accept(this); - if (fina1) { - statement.setFinal(true); - } + statement.setFinal(fina1); } @Override public void visit(LocalVariableDeclaration declaration) { fina1 = false; declaration.getLocalVariableDeclarators().accept(this); - if (fina1) { - declaration.setFinal(true); - } + declaration.setFinal(fina1); } @Override public void visit(LocalVariableDeclarator declarator) { - if (finalLocalVariableNameSet.contains(declarator.getName())) { + if (finalLocalVariableNameMap.containsKey(declarator.getName())) { fina1 = true; - declarator.setName(declarator.getName()); + declarator.setName(finalLocalVariableNameMap.get(declarator.getName())); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java index 8986f761..91087b09 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java @@ -10,13 +10,20 @@ import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.Map; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS_WILDCARD; + public class PopulateBindingsWithTypeArgumentVisitor implements TypeArgumentVisitor { protected TypeArgumentToTypeVisitor typeArgumentToTypeVisitor = new TypeArgumentToTypeVisitor(); protected TypeMaker typeMaker; + protected Map contextualTypeBounds; protected Map bindings; + protected Map typeBounds; protected BaseTypeArgument current; public PopulateBindingsWithTypeArgumentVisitor(TypeMaker typeMaker) { @@ -24,8 +31,10 @@ public PopulateBindingsWithTypeArgumentVisitor(TypeMaker typeMaker) { this.current = null; } - public void init(Map bindings, BaseTypeArgument typeArgument) { + public void init(Map contextualTypeBounds, Map bindings, Map typeBounds, BaseTypeArgument typeArgument) { + this.contextualTypeBounds = contextualTypeBounds; this.bindings = bindings; + this.typeBounds = typeBounds; this.current = typeArgument; } @@ -43,57 +52,87 @@ public void visit(TypeArguments arguments) { } @Override public void visit(GenericType type) { - if (bindings.containsKey(type.getName())) { + String typeName = type.getName(); + + if (bindings.containsKey(typeName)) { TypeArgument typeArgument = bindings.get(type.getName()); - if (typeArgument == null) { - if (current == null) { - bindings.put(type.getName(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); - } else { - bindings.put(type.getName(), (TypeArgument) current); + if (current != null) { + if ((current.getClass() == GenericType.class) && !equals(contextualTypeBounds.get(typeName), typeBounds.get(((GenericType)current).getName()))) { + return; // Incompatible bounds } - } else if ((current != null) && !current.equals(typeArgument)) { - typeArgumentToTypeVisitor.init(); - typeArgument.accept(typeArgumentToTypeVisitor); - Type t1 = typeArgumentToTypeVisitor.getType(); - - typeArgumentToTypeVisitor.init(); - current.accept(typeArgumentToTypeVisitor); - Type t2 = typeArgumentToTypeVisitor.getType(); - - if (!t1.createType(0).equals(t2.createType(0))) { - if (t1.isObject() && t2.isObject()) { - ObjectType ot1 = (ObjectType)t1; - ObjectType ot2 = (ObjectType)t2; - - if (typeMaker.isAssignable(ot1, ot2)) { - bindings.put(type.getName(), typeArgument); - } else if (typeMaker.isAssignable(ot2, ot1)) { - bindings.put(type.getName(), (TypeArgument) current); - } else { - bindings.put(type.getName(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + + if (typeArgument == null) { + bindings.put(typeName, convertCurrentTypeArgument()); + } else if (!current.equals(typeArgument)) { + typeArgumentToTypeVisitor.init(); + typeArgument.accept(typeArgumentToTypeVisitor); + Type t1 = typeArgumentToTypeVisitor.getType(); + + typeArgumentToTypeVisitor.init(); + current.accept(typeArgumentToTypeVisitor); + Type t2 = typeArgumentToTypeVisitor.getType(); + + if (!t1.createType(0).equals(t2.createType(0))) { + if (t1.isObject() && t2.isObject()) { + ObjectType ot1 = (ObjectType)t1; + ObjectType ot2 = (ObjectType)t2; + + if (typeMaker.isAssignable(ot1, ot2)) { + bindings.put(typeName, typeArgument); + } else if (typeMaker.isAssignable(ot2, ot1)) { + bindings.put(typeName, convertCurrentTypeArgument()); + } else { + bindings.put(typeName, WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } } - } else { - bindings.put(type.getName(), WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); } } } } } + protected boolean equals(BaseType bt1, BaseType bt2) { + if (bt1 == null) { + return (bt2 == null); + } else { + return (bt2 != null) && bt1.equals(bt2); + } + } + + protected TypeArgument convertCurrentTypeArgument() { + if ((current != null) && (current.getClass() == ObjectType.class)) { + ObjectType ot = (ObjectType)current; + + if ((ot.getTypeArguments() == null) && ot.getInternalName().equals(TYPE_CLASS.getInternalName())) { + return TYPE_CLASS_WILDCARD; + } + } + + return (TypeArgument)current; + } + @Override public void visit(WildcardExtendsTypeArgument type) { - if ((current != null) && (current.getClass() == WildcardExtendsTypeArgument.class)) { - current = ((WildcardExtendsTypeArgument) current).getType(); - type.getType().accept(this); + if (current != null) { + if (current.getClass() == WildcardExtendsTypeArgument.class) { + current = ((WildcardExtendsTypeArgument) current).getType(); + type.getType().accept(this); + } else { + type.getType().accept(this); + } } } @Override public void visit(WildcardSuperTypeArgument type) { - if ((current != null) && (current.getClass() == WildcardSuperTypeArgument.class)) { - current = ((WildcardSuperTypeArgument) current).getType(); - type.getType().accept(this); + if (current != null) { + if (current.getClass() == WildcardSuperTypeArgument.class) { + current = ((WildcardSuperTypeArgument) current).getType(); + type.getType().accept(this); + } else { + type.getType().accept(this); + } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java index 5cae47d2..1c107506 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java @@ -13,9 +13,11 @@ public class PopulateBindingsWithTypeParameterVisitor implements TypeParameterVisitor { protected Map bindings = null; + protected Map typeBounds = null; - public void init(Map bindings) { + public void init(Map bindings, Map typeBounds) { this.bindings = bindings; + this.typeBounds = typeBounds; } @Override @@ -26,6 +28,7 @@ public void visit(TypeParameter type) { @Override public void visit(TypeParameterWithTypeBounds type) { bindings.put(type.getIdentifier(), null); + typeBounds.put(type.getIdentifier(), type.getTypeBounds()); } @Override diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java index d6ef77ed..6314edcd 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/TypeArgumentToTypeVisitor.java @@ -23,7 +23,6 @@ public Type getType() { return type; } - @Override public void visit(TypeArguments arguments) { type = TYPE_UNDEFINED_OBJECT; } @Override public void visit(DiamondTypeArgument argument) { type = TYPE_OBJECT; } @Override public void visit(WildcardTypeArgument argument) { type = TYPE_OBJECT; } @@ -35,4 +34,11 @@ public Type getType() { @Override public void visit(WildcardExtendsTypeArgument argument) { argument.getType().accept(this); } @Override public void visit(WildcardSuperTypeArgument argument) { argument.getType().accept(this); } + @Override public void visit(TypeArguments arguments) { + if (arguments.isEmpty()) { + type = TYPE_UNDEFINED_OBJECT; + } else { + arguments.getFirst().accept(this); + } + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java index 2f695112..b2bd60cb 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -20,6 +20,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeParametersToTypeArgumentsBinder; import org.jd.core.v1.util.DefaultList; @@ -31,6 +32,11 @@ public class UpdateBridgeMethodVisitor extends AbstractUpdateExpressionVisitor { protected BodyDeclarationsVisitor bodyDeclarationsVisitor = new BodyDeclarationsVisitor(); protected HashMap> bridgeMethodDeclarations = new HashMap<>(); + protected TypeMaker typeMaker; + + public UpdateBridgeMethodVisitor(TypeMaker typeMaker) { + this.typeMaker = typeMaker; + } public boolean init(ClassFileBodyDeclaration bodyDeclaration) { bridgeMethodDeclarations.clear(); @@ -99,35 +105,31 @@ protected Expression updateExpression(Expression expression) { return new FieldReferenceExpression(mie1.getLineNumber(), fre.getType(), expression, fre.getInternalTypeName(), fre.getName(), fre.getDescriptor()); } else if (expClass == ClassFileMethodInvocationExpression.class) { MethodInvocationExpression mie2 = (MethodInvocationExpression) exp; + TypeMaker.MethodTypes methodTypes = typeMaker.makeMethodTypes(mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor()); - if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { - return new ClassFileMethodInvocationExpression(null, mie1.getLineNumber(), null, mie2.getType(), mie2.getExpression(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), mie1.getParameterTypes(), mie1.getParameters()); - } else { - BaseType mie1ParameterTypes = mie1.getParameterTypes(); - BaseExpression mie1Parameters = mie1.getParameters(); - BaseType newParameterTypes = null; - BaseExpression newParameters = null; + if (methodTypes != null) { + if ((mie2.getExpression().getClass() == ObjectTypeReferenceExpression.class)) { + // Static method invocation + return new ClassFileMethodInvocationExpression(null, mie1.getLineNumber(), null, methodTypes.returnedType, mie2.getExpression(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), methodTypes.parameterTypes, mie1.getParameters()); + } else { + BaseExpression mie1Parameters = mie1.getParameters(); + BaseExpression newParameters = null; - if (mie1Parameters != null) { switch (mie1Parameters.size()) { case 0: case 1: break; case 2: - Expression e = mie1Parameters.getList().get(1); - newParameterTypes = e.getType(); - newParameters = e; + newParameters = mie1Parameters.getList().get(1); break; default: - DefaultList t = mie1ParameterTypes.getList(); - newParameterTypes = new Types(t.subList(1, t.size())); DefaultList p = mie1Parameters.getList(); newParameters = new Expressions(p.subList(1, p.size())); break; } - } - return new ClassFileMethodInvocationExpression(null, mie1.getLineNumber(), null, mie2.getType(), mie1Parameters.getFirst(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), newParameterTypes, newParameters); + return new ClassFileMethodInvocationExpression(mie1.getBinder(), mie1.getLineNumber(), null, methodTypes.returnedType, mie1Parameters.getFirst(), mie2.getInternalTypeName(), mie2.getName(), mie2.getDescriptor(), methodTypes.parameterTypes, newParameters); + } } } else if (expClass == BinaryOperatorExpression.class) { BinaryOperatorExpression boe = (BinaryOperatorExpression) exp; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateClassTypeArgumentsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateClassTypeArgumentsVisitor.java new file mode 100644 index 00000000..08c37c31 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateClassTypeArgumentsVisitor.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS_WILDCARD; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; + +public class UpdateClassTypeArgumentsVisitor extends AbstractTypeArgumentVisitor { + protected BaseTypeArgument result; + + public void init() { + this.result = null; + } + + public BaseTypeArgument getTypeArgument() { + return result; + } + + @Override + public void visit(WildcardExtendsTypeArgument argument) { + Type type = argument.getType(); + + type.accept(this); + + result = (result == type) ? argument : new WildcardExtendsTypeArgument((Type)result); + } + + @Override + public void visit(WildcardSuperTypeArgument argument) { + Type type = argument.getType(); + + type.accept(this); + + result = (result == type) ? argument : new WildcardSuperTypeArgument((Type)result); + } + + @Override public void visit(DiamondTypeArgument argument) { result = argument; } + @Override public void visit(WildcardTypeArgument argument) { result = argument; } + + @Override public void visit(PrimitiveType type) { result = type; } + @Override public void visit(GenericType type) { result = type; } + + @Override + public void visit(ObjectType type) { + BaseTypeArgument typeArguments = type.getTypeArguments(); + + if (typeArguments == null) { + if (type.getInternalName().equals(TYPE_CLASS.getInternalName())) { + result = TYPE_CLASS_WILDCARD; + } else { + result = type; + } + } else { + typeArguments.accept(this); + + if (result == typeArguments) { + result = type; + } else { + result = type.createType(typeArguments); + } + } + } + + @Override + public void visit(InnerObjectType type) { + type.getOuterType().accept(this); + + BaseTypeArgument typeArguments = type.getTypeArguments(); + + if (type.getOuterType() == result) { + if (typeArguments == null) { + result = type; + } else { + typeArguments.accept(this); + result = (result == typeArguments) ? type : type.createType(result); + } + } else { + ObjectType outerObjectType = (ObjectType) result; + + if (typeArguments != null) { + typeArguments.accept(this); + typeArguments = result; + } + + result = new InnerObjectType(type.getInternalName(), type.getQualifiedName(), type.getName(), typeArguments, type.getDimension(), outerObjectType); + } + } + + @Override + public void visit(TypeArguments arguments) { + int size = arguments.size(); + int i; + + for (i=0; i= 51)) { // (majorVersion >= Java 7) + objectType = objectType.createType(DiamondTypeArgument.DIAMOND); + } + + BaseType type = objectType; type.accept(this); tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index f2ca2423..a512b2df 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -76,7 +76,7 @@ public void testJdk170Basic() throws Exception { assertTrue(source.indexOf("char c3 = '\\'';") != -1); assertTrue(source.indexOf("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');") != -1); assertTrue(source.indexOf("Class class3 = String.class, class2 = class3, class1 = class2;") != -1); - assertTrue(source.matches(PatternMaker.make("Class class5 = doSomething(class6 = String.class, args1 = args2 = new String[], class4 = class5;"))); + assertTrue(source.matches(PatternMaker.make("Class class5 = doSomething(class6 = String.class, args1 = args2 = new String[], class4 = class5;"))); assertTrue(source.matches(PatternMaker.make("int j = 1, k[] = {1, l[][] = {"))); assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); @@ -126,7 +126,7 @@ public void testJdk170Basic() throws Exception { } @Test - public void testJdk170NoDebugBasic() throws Exception { + public void testJdk170NoDebugInfoBasic() throws Exception { String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); Loader loader = new ZipLoader(is); @@ -159,7 +159,7 @@ public void testJdk170NoDebugBasic() throws Exception { assertTrue(source.matches(PatternMaker.make("Class clazz3 = String.class;"))); assertTrue(source.matches(PatternMaker.make("Class clazz2 = clazz3;"))); assertTrue(source.matches(PatternMaker.make("Class clazz1 = clazz2;"))); - assertTrue(source.indexOf("Class clazz5 = doSomething(clazz6 = String.class, arrayOfString1 = arrayOfString2 = new String[]") != -1); + assertTrue(source.indexOf("Class clazz5 = doSomething(clazz6 = String.class, arrayOfString1 = arrayOfString2 = new String[]") != -1); assertTrue(source.matches(PatternMaker.make("if (this instanceof Object)"))); @@ -726,7 +726,7 @@ public void testJdk170For() throws Exception { } @Test - public void testJdk170NoDebugFor() throws Exception { + public void testJdk170NoDebugInfoFor() throws Exception { String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); Loader loader = new ZipLoader(is); @@ -734,7 +734,7 @@ public void testJdk170NoDebugFor() throws Exception { PlainTextPrinter printer = new PlainTextPrinter(); Message message = new Message(); - message.setHeader("mainInternalTypeName", "org/jd/core/test/For"); + message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); @@ -800,7 +800,7 @@ public void testJdk150For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 345 */", "while (b < 10);"))); assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String str : paramArrayOfString)"))); assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String str : paramList)"))); - assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.matches(PatternMaker.make(": 423 */", "for (byte b = 0; b < 3; b++)"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -1079,11 +1079,13 @@ public void testJdk150AnonymousClass() throws Exception { Loader loader = new ZipLoader(is); //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); Message message = new Message(); message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); + message.setHeader("configuration", configuration); deserializer.process(message); converter.process(message); @@ -1114,6 +1116,7 @@ public void testJdk150AnonymousClass() throws Exception { assertTrue(source.matches(PatternMaker.make(": 96 */", "return (abc.equals(param2Object) || def.equals(param2Object) || str1.equals(param2Object) || str2.equals(param2Object));"))); assertTrue(source.matches(PatternMaker.make(": 104 */", "System.out.println(\"end\");"))); + assertTrue(source.indexOf("/* 111: 111 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors @@ -2052,9 +2055,9 @@ public void testJdk170GenericClass() throws Exception { assertTrue(source.indexOf("extends ArrayList") != -1); assertTrue(source.indexOf("implements Serializable, Comparable") != -1); - assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "public List> list1 = new ArrayList();"))); + assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "public List> list1 = new ArrayList<>();"))); assertTrue(source.indexOf("public List> list2;") != -1); - assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "list2 = new ArrayList();"))); + assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "list2 = new ArrayList<>();"))); assertTrue(source.indexOf("public void fromArrayToCollection(T[] a, Collection c)") != -1); assertTrue(source.indexOf("public void copy(List dest, List src)") != -1); @@ -2145,7 +2148,7 @@ public void testJdk170AnnotationValue() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 11: 0 */", "boolean z() default true;"))); assertTrue(source.matches(PatternMaker.make("/* 13: 0 */", "byte b() default 1;"))); assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "String str() default \"str\";"))); - assertTrue(source.matches(PatternMaker.make("/* 27: 0 */", "Class clazz() default Object.class;"))); + assertTrue(source.matches(PatternMaker.make("/* 27: 0 */", "Class clazz() default Object.class;"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -2584,7 +2587,7 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 20 */", "list.stream().filter(s -> (s != null)).forEach(s -> System.out.println(s));"))); assertTrue(source.indexOf("Predicate filter = s -> (s.length() == length);") != -1); assertTrue(source.indexOf("Consumer println = s -> System.out.println(s);") != -1); - assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter((Predicate)filter).forEach((Consumer)println);"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter(filter).forEach(println);"))); assertTrue(source.matches(PatternMaker.make(": 31 */", "((Map)list.stream()"))); assertTrue(source.matches(PatternMaker.make(": 32 */", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))"))); assertTrue(source.matches(PatternMaker.make(": 33 */", ".forEach((key, value) ->"))); @@ -2595,7 +2598,7 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 61 */", "Supplier constructorReference = String::new;"))); assertTrue(source.matches(PatternMaker.make(": 65 */", "MethodType mtToString = MethodType.methodType(String.class);"))); assertTrue(source.matches(PatternMaker.make(": 66 */", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); - assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); assertTrue(source.indexOf("// Byte code:") == -1); diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 4ebc2ff0..daee76a3 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -25,8 +25,7 @@ import java.io.FileInputStream; import java.io.InputStream; import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class JarFileToJavaSourceTest extends TestCase { protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); @@ -72,6 +71,9 @@ protected void test(InputStream inputStream) throws Exception { for (String path : loader.getMap().keySet()) { if (path.endsWith(".class") && (path.indexOf('$') == -1)) { String internalTypeName = path.substring(0, path.length() - 6); // 6 = ".class".length() + + if (!internalTypeName.endsWith("/ListOrderedMap")) continue; // TODO + message.setHeader("mainInternalTypeName", internalTypeName); printer.init(); @@ -137,7 +139,7 @@ protected void test(InputStream inputStream) throws Exception { assertTrue(exceptionCounter == 0); assertTrue(assertFailedCounter == 0); - // TODO assertTrue(recompilationFailedCounter == 0); + assertTrue(recompilationFailedCounter == 0); } } diff --git a/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java index c2e60225..0703f04c 100644 --- a/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java +++ b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java @@ -255,7 +255,7 @@ protected DefaultList newInnerTypes(int lineNumber) DefaultList fields = new DefaultList<>(); fields.add(new ClassFileFieldDeclaration(0, PrimitiveType.TYPE_INT, new FieldDeclarator("d"), lineNumber)); - ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration("A", null, null); + ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration("A", null, null, null); bodyDeclaration.setFieldDeclarations(fields); innerTypes.add(new ClassFileClassDeclaration(null, 0, "A", "A", null, null, null, bodyDeclaration)); diff --git a/src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java b/src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java index 0dd95bec..15a32766 100644 --- a/src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java +++ b/src/test/java/org/jd/core/v1/PopulateBindingsForStaticMethodVisitorTest.java @@ -42,13 +42,15 @@ public void test() throws Exception { // Create bindings PopulateBindingsWithTypeArgumentVisitor visitor = new PopulateBindingsWithTypeArgumentVisitor(new TypeMaker(new ClassPathLoader())); HashMap bindings = new HashMap<>(); + HashMap typeBounds = new HashMap<>(); + bindings.put("I", null); bindings.put("O", null); - visitor.init(bindings, returnedType); + visitor.init(typeBounds, bindings, typeBounds, returnedType); genericReturnedType.accept(visitor); - visitor.init(bindings, parameterTypes); + visitor.init(typeBounds, bindings, typeBounds, parameterTypes); genericParameterTypes.accept(visitor); // Result: bindings[I:Integer, O:? extends String] diff --git a/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java b/src/test/java/org/jd/core/v1/TypeMakerTest.java similarity index 54% rename from src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java rename to src/test/java/org/jd/core/v1/TypeMakerTest.java index d64e3308..95e3f3a2 100644 --- a/src/test/java/org/jd/core/v1/ObjectTypeMakerTest.java +++ b/src/test/java/org/jd/core/v1/TypeMakerTest.java @@ -8,21 +8,41 @@ package org.jd.core.v1; import junit.framework.TestCase; +import org.apache.commons.collections4.iterators.AbstractUntypedIteratorDecorator; import org.jd.core.v1.loader.ClassPathLoader; import org.jd.core.v1.loader.ZipLoader; import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.model.javasyntax.type.TypeArguments; +import org.jd.core.v1.model.javasyntax.type.WildcardExtendsTypeArgument; +import org.jd.core.v1.model.javasyntax.type.WildcardSuperTypeArgument; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.junit.Test; import java.io.InputStream; - -public class ObjectTypeMakerTest extends TestCase { +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.PrimitiveIterator; + +public class TypeMakerTest extends TestCase { + protected TypeMaker typeMaker = new TypeMaker(new ClassPathLoader()); + + protected ObjectType otAbstractUntypedIteratorDecorator = makeObjectType(AbstractUntypedIteratorDecorator.class); + protected ObjectType otArrayList = makeObjectType(ArrayList.class); + protected ObjectType otInteger = makeObjectType(Integer.class); + protected ObjectType otIterator = makeObjectType(Iterator.class); + protected ObjectType otList = makeObjectType(List.class); + protected ObjectType otNumber = makeObjectType(Number.class); + protected ObjectType otPrimitiveIterator = makeObjectType(PrimitiveIterator.class); + + protected ObjectType makeObjectType(Class clazz) { + return typeMaker.makeFromInternalTypeName(clazz.getName().replace('.', '/')); + } @Test public void testOuterClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass"); assertEquals("org/jd/core/test/OuterClass", ot.getInternalName()); @@ -33,8 +53,7 @@ public void testOuterClass() throws Exception { @Test public void testOuterClass$InnerClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$InnerClass"); assertEquals("org/jd/core/test/OuterClass$InnerClass", ot.getInternalName()); @@ -45,8 +64,7 @@ public void testOuterClass() throws Exception { @Test public void testOuterClass$StaticInnerClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$StaticInnerClass"); assertEquals("org/jd/core/test/OuterClass$StaticInnerClass", ot.getInternalName()); @@ -57,8 +75,7 @@ public void testOuterClass() throws Exception { @Test public void testOuterClass$1() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$1"); assertEquals("org/jd/core/test/OuterClass$1", ot.getInternalName()); @@ -69,8 +86,7 @@ public void testOuterClass() throws Exception { @Test public void testOuterClass$1LocalClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType ot = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$1LocalClass"); assertEquals("org/jd/core/test/OuterClass$1LocalClass", ot.getInternalName()); @@ -80,8 +96,6 @@ public void testOuterClass() throws Exception { @Test public void testThread() throws Exception { - ClassPathLoader loader = new ClassPathLoader(); - TypeMaker typeMaker = new TypeMaker(loader); ObjectType ot = typeMaker.makeFromInternalTypeName("java/lang/Thread"); assertEquals("java/lang/Thread", ot.getInternalName()); @@ -91,8 +105,6 @@ public void testThread() throws Exception { @Test public void testThreadState() throws Exception { - ClassPathLoader loader = new ClassPathLoader(); - TypeMaker typeMaker = new TypeMaker(loader); ObjectType ot = typeMaker.makeFromInternalTypeName("java/lang/Thread$State"); assertEquals("java/lang/Thread$State", ot.getInternalName()); @@ -102,8 +114,6 @@ public void testThreadState() throws Exception { @Test public void testUnknownClass() throws Exception { - ClassPathLoader loader = new ClassPathLoader(); - TypeMaker typeMaker = new TypeMaker(loader); ObjectType ot = typeMaker.makeFromInternalTypeName("org/unknown/Class"); assertEquals("org/unknown/Class", ot.getInternalName()); @@ -113,8 +123,6 @@ public void testUnknownClass() throws Exception { @Test public void testUnknownInnerClass() throws Exception { - ClassPathLoader loader = new ClassPathLoader(); - TypeMaker typeMaker = new TypeMaker(loader); ObjectType ot = typeMaker.makeFromInternalTypeName("org/unknown/Class$InnerClass"); assertEquals("org/unknown/Class$InnerClass", ot.getInternalName()); @@ -124,8 +132,6 @@ public void testUnknownInnerClass() throws Exception { @Test public void testListIsAssignableFromArrayList() throws Exception { - ClassPathLoader loader = new ClassPathLoader(); - TypeMaker typeMaker = new TypeMaker(loader); ObjectType parent = typeMaker.makeFromInternalTypeName("java/util/List"); ObjectType child = typeMaker.makeFromInternalTypeName("java/util/ArrayList"); @@ -136,8 +142,6 @@ public void testListIsAssignableFromArrayList() throws Exception { @Test public void testClassIsAssignableFromObject() throws Exception { - ClassPathLoader loader = new ClassPathLoader(); - TypeMaker typeMaker = new TypeMaker(loader); ObjectType parent = typeMaker.makeFromInternalTypeName("java/lang/Class"); ObjectType child = typeMaker.makeFromInternalTypeName("java/lang/Object"); @@ -149,8 +153,7 @@ public void testClassIsAssignableFromObject() throws Exception { @Test public void testObjectIsAssignableFromSafeNumberComparator() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType parent = typeMaker.makeFromInternalTypeName("java/lang/Object"); ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); @@ -162,8 +165,7 @@ public void testObjectIsAssignableFromSafeNumberComparator() throws Exception { @Test public void testComparatorIsAssignableFromSafeNumberComparator() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType parent = typeMaker.makeFromInternalTypeName("java/util/Comparator"); ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); @@ -175,8 +177,7 @@ public void testComparatorIsAssignableFromSafeNumberComparator() throws Exceptio @Test public void testNumberComparatorIsAssignableFromSafeNumberComparator() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType parent = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$NumberComparator"); ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass$SafeNumberComparator"); @@ -188,8 +189,7 @@ public void testNumberComparatorIsAssignableFromSafeNumberComparator() throws Ex @Test public void testOuterClassIsAssignableFromSimpleClass() throws Exception { InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - ZipLoader loader = new ZipLoader(is); - TypeMaker typeMaker = new TypeMaker(loader); + TypeMaker typeMaker = new TypeMaker(new ZipLoader(is)); ObjectType parent = typeMaker.makeFromInternalTypeName("org/jd/core/test/OuterClass"); ObjectType child = typeMaker.makeFromInternalTypeName("org/jd/core/test/SimpleClass"); @@ -197,4 +197,140 @@ public void testOuterClassIsAssignableFromSimpleClass() throws Exception { assertNotNull(child); assertFalse(typeMaker.isAssignable(parent, child)); } + @Test + public void testListAssignment() throws Exception { + List list1 = null; + List list2 = null; + + ObjectType ot1 = otList; + ObjectType ot2 = otList; + + // Valid: list1 = list2; + assertTrue(typeMaker.isAssignable(ot1, ot2)); + + // Valid: list2 = list1; + assertTrue(typeMaker.isAssignable(ot2, ot1)); + } + + @Test + public void testListAndArrayListAssignment() throws Exception { + List list1 = null; + ArrayList list2 = null; + + ObjectType ot1 = otList; + ObjectType ot2 = otArrayList; + + // Valid: list1 = list2; + assertTrue(typeMaker.isAssignable(ot1, ot2)); + + // Invalid: list2 = list1; + assertFalse(typeMaker.isAssignable(ot2, ot1)); + } + + @Test + public void testListNumberAndArrayListNumberAssignment() throws Exception { + List list1 = null; + ArrayList list2 = null; + + ObjectType ot1 = otList.createType(otNumber); + ObjectType ot2 = otArrayList.createType(otNumber); + + // Valid: list1 = list2; + assertTrue(typeMaker.isAssignable(ot1, ot2)); + + // Invalid: list2 = list1; + assertFalse(typeMaker.isAssignable(ot2, ot1)); + } + + @Test + public void testListNumberAndListIntegerAssignment() throws Exception { + List list1 = null; + List list2 = null; + + ObjectType ot1 = otList.createType(otNumber); + ObjectType ot2 = otList.createType(otInteger); + + // Invalid: list1 = list2; + assertFalse(typeMaker.isAssignable(ot1, ot2)); + + // Invalid: list2 = list1; + assertFalse(typeMaker.isAssignable(ot2, ot1)); + } + + @Test + public void testListNumberAndListExtendsNumberAssignment() throws Exception { + List list1 = null; + List list2 = null; + + ObjectType ot1 = otList.createType(otNumber); + ObjectType ot2 = otList.createType(new WildcardExtendsTypeArgument(otNumber)); + + // Invalid: list1 = list2; + assertFalse(typeMaker.isAssignable(ot1, ot2)); + + // Valid: list2 = list1; + assertTrue(typeMaker.isAssignable(ot2, ot1)); + } + + @Test + public void testListNumberAndListSuperNumberAssignment() throws Exception { + List list1 = null; + List list2 = null; + + ObjectType ot1 = otList.createType(otNumber); + ObjectType ot2 = otList.createType(new WildcardSuperTypeArgument(otNumber)); + + // Invalid: list1 = list2; + assertFalse(typeMaker.isAssignable(ot1, ot2)); + + // Valid: list2 = list1; + assertTrue(typeMaker.isAssignable(ot2, ot1)); + } + + @Test + public void testListNumberAndArrayListIntegerAssignment() throws Exception { + List list1 = null; + ArrayList list2 = null; + + ObjectType ot1 = otList.createType(otNumber); + ObjectType ot2 = otArrayList.createType(otInteger); + + // Invalid: list1 = list2; + assertFalse(typeMaker.isAssignable(ot1, ot2)); + + // Invalid: list2 = list1; + assertFalse(typeMaker.isAssignable(ot2, ot1)); + } + + @Test + public void testIteratorNumberAndPrimitiveIteratorNumberAssignment() throws Exception { + Iterator iterator1 = null; + PrimitiveIterator iterator2 = null; + + TypeArguments tas = new TypeArguments(); + tas.add(otNumber); + tas.add(otList); + + ObjectType ot1 = otIterator.createType(otNumber); + ObjectType ot2 = otPrimitiveIterator.createType(tas); + + // Valid: iterator1 = iterator2; + assertTrue(typeMaker.isAssignable(ot1, ot2)); + } + + @Test + public void testIteratorNumberAndAbstractUntypedIteratorDecoratorNumberAssignment() throws Exception { + Iterator iterator1 = null; + AbstractUntypedIteratorDecorator iterator2 = null; + + TypeArguments tas = new TypeArguments(); + tas.add(otList); + tas.add(otNumber); + + ObjectType ot1 = otIterator.createType(otNumber); + ObjectType ot2 = otAbstractUntypedIteratorDecorator.createType(tas); + + // Valid: iterator1 = iterator2; + assertTrue(typeMaker.isAssignable(ot1, ot2)); + } } diff --git a/src/test/resources/java/org/jd/core/test/AnonymousClass.java b/src/test/resources/java/org/jd/core/test/AnonymousClass.java index 0466b7ea..074f1eb3 100644 --- a/src/test/resources/java/org/jd/core/test/AnonymousClass.java +++ b/src/test/resources/java/org/jd/core/test/AnonymousClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -16,102 +16,102 @@ public class AnonymousClass { - protected long time = System.currentTimeMillis(); - - public void test(Enumeration e, String s) { - System.out.println("start"); - - Object obj = new Object() { - public String toString() { - return "toString() return " + super.toString() + " at " + time; - } - }; - - System.out.println(obj); - - System.out.println("end"); - } - - LinkedList list; - - public void anonymousImplInterface(final String s1, @Name("s2") final String s2, String s3, final int i1) { - System.out.println("start"); - - final long l1 = System.currentTimeMillis(); - - Enumeration e = new Enumeration() { - Iterator i = list.iterator(); - - public boolean hasMoreElements() { - time = System.currentTimeMillis(); - return i.hasNext() && (s1 == s2) && (i1 > l1); - } - - public Object nextElement() { - return i.next(); - } - }; - - test(e, - "test"); - - System.out.println("end"); - } - - public void anonymousImplClass(final String s1, final String s2, String s3) { - System.out.println("start"); - - final int i = s1.length(); - - System.out.println("2" + (new StringWrapper(123456L) { - - public String toString(String a, String b) { - time = System.currentTimeMillis(); - if ((s1 == s2) && (i == 5)) - return s1; - else - return s2; - } - - }) + "3"); - - System.out.println("end"); - } - - public void twoAnonymousClasses() { - System.out.println("start"); - - final Object abc = "abc"; - final Object def = "def"; - - Serializable serializable = new Serializable() { - public boolean equals(Object obj) { - - final Object ghi = "ghi"; - final Object jkl = "jkl"; - - Serializable serializable = new Serializable() { - public boolean equals(Object obj) { - - Object ghi = "overwrite ghi"; - Object jkl = "overwrite jkl"; - - return abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj); - } - }; - - return abc.equals(obj) || def.equals(obj); - } - }; - - System.out.println("end"); - } - - public static class StringWrapper { - protected long l; - - public StringWrapper(long l) { - this.l = l & 128L; - } - } + protected long time = System.currentTimeMillis(); + + public void test(Enumeration e, String s) { + System.out.println("start"); + + Object obj = new Object() { + public String toString() { + return "toString() return " + super.toString() + " at " + time; + } + }; + + System.out.println(obj); + + System.out.println("end"); + } + + LinkedList list; + + public void anonymousImplInterface(final String s1, @Name("s2") final String s2, String s3, final int i1) { + System.out.println("start"); + + final long l1 = System.currentTimeMillis(); + + Enumeration e = new Enumeration() { + Iterator i = list.iterator(); + + public boolean hasMoreElements() { + time = System.currentTimeMillis(); + return i.hasNext() && (s1 == s2) && (i1 > l1); + } + + public Object nextElement() { + return i.next(); + } + }; + + test(e, + "test"); + + System.out.println("end"); + } + + public void anonymousImplClass(final String s1, final String s2, String s3) { + System.out.println("start"); + + final int i = s1.length(); + + System.out.println("2" + (new StringWrapper(123456L) { + + public String toString(String a, String b) { + time = System.currentTimeMillis(); + if ((s1 == s2) && (i == 5)) + return s1; + else + return s2; + } + + }) + "3"); + + System.out.println("end"); + } + + public void twoAnonymousClasses() { + System.out.println("start"); + + final Object abc = "abc"; + final Object def = "def"; + + Serializable serializable = new Serializable() { + public boolean equals(Object obj) { + + final Object ghi = "ghi"; + final Object jkl = "jkl"; + + Serializable serializable = new Serializable() { + public boolean equals(Object obj) { + + Object ghi = "overwrite ghi"; + Object jkl = "overwrite jkl"; + + return abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj); + } + }; + + return abc.equals(obj) || def.equals(obj); + } + }; + + System.out.println("end"); + } + + public static class StringWrapper { + protected long l; + + public StringWrapper(long l) { + this.l = l & 128L; + } + } } From 0491b5fddb8a45f8ddadfe4568d7fe87261c0b0f Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 1 Nov 2019 09:04:48 +0100 Subject: [PATCH 080/211] Update test --- src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index daee76a3..531b253d 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -72,8 +72,6 @@ protected void test(InputStream inputStream) throws Exception { if (path.endsWith(".class") && (path.indexOf('$') == -1)) { String internalTypeName = path.substring(0, path.length() - 6); // 6 = ".class".length() - if (!internalTypeName.endsWith("/ListOrderedMap")) continue; // TODO - message.setHeader("mainInternalTypeName", internalTypeName); printer.init(); From 6d2822a0936ea3c46a1c47cfe2eb2f28a3dcb506 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 1 Nov 2019 09:05:56 +0100 Subject: [PATCH 081/211] Update version to 1.1.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d11990d6..6c46835a 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'org.apache.commons:commons-collections4:4.1' } -version='1.0.9' +version='1.1.0' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From 95063826346beedee0157815318db8e24d737405 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 1 Nov 2019 09:11:00 +0100 Subject: [PATCH 082/211] Fix warnings --- .../classfiletojavasyntax/model/localvariable/Frame.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 59180539..9dd1fd57 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -26,7 +26,7 @@ public class Frame { protected static final AbstractLocalVariableComparator ABSTRACT_LOCAL_VARIABLE_COMPARATOR = new AbstractLocalVariableComparator(); - protected static final HashSet CAPITALIZED_JAVA_LANGUAGE_KEYWORDS = new HashSet(Arrays.asList( + protected static final HashSet CAPITALIZED_JAVA_LANGUAGE_KEYWORDS = new HashSet<>(Arrays.asList( "Abstract", "Continue", "For", "New", "Switch", "Assert", "Default", "Goto", "Package", "Synchronized", "Boolean", "Do", "If", "Private", "This", "Break", "Double", "Implements", "Protected", "Throw", "Byte", "Else", "Import", "Public", "Throws", "Case", "Enum", "Instanceof", "Return", "Transient", "Catch", "Extends", "Int", From 7fa1b8f171bca1b509e8aa4e49124226b31f5e9c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 1 Nov 2019 15:19:27 +0100 Subject: [PATCH 083/211] Quick fixes --- build.gradle | 2 +- .../expression/ArrayExpression.java | 2 - .../v1/model/javasyntax/type/ObjectType.java | 2 +- .../model/javasyntax/type/PrimitiveType.java | 2 +- .../localvariable/ObjectLocalVariable.java | 12 ++++-- .../util/ByteCodeParser.java | 7 ++-- .../classfiletojavasyntax/util/TypeMaker.java | 6 +-- .../TypeParametersToTypeArgumentsBinder.java | 31 ++++++++------ .../visitor/AddCastExpressionVisitor.java | 19 ++++++--- ...dTypeParametersToTypeArgumentsVisitor.java | 3 +- ...pulateBindingsWithTypeArgumentVisitor.java | 41 +++++++++++-------- 11 files changed, 76 insertions(+), 51 deletions(-) diff --git a/build.gradle b/build.gradle index 6c46835a..5f441c7a 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ dependencies { testCompile 'org.apache.commons:commons-collections4:4.1' } -version='1.1.0' +version='1.1.1' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java index aaa0ac7f..1ac38159 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java @@ -52,8 +52,6 @@ protected static Type createItemType(Expression expression) { Type type = expression.getType(); int dimension = type.getDimension(); - assert (type == TYPE_UNDEFINED_OBJECT) || (dimension > 0) : "ArrayExpression.createItemType(exp) : zero or negative dimension"; - return type.createType((dimension > 0) ? dimension-1 : 0); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index 258d420e..b9ec7d46 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -137,7 +137,7 @@ public int getDimension() { @Override public Type createType(int dimension) { - assert dimension >= 0 : "ObjectType.createType(dim) : create type with zero or negative dimension"; + assert dimension >= 0 : "ObjectType.createType(dim) : create type with negative dimension"; if (this.dimension == dimension) { return this; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java index f9e236ca..4eedc364 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java @@ -123,7 +123,7 @@ public int getRightFlags() { @Override public Type createType(int dimension) { - assert dimension >= 0 : "PrimitiveType.createType(dim) : create type with zero or negative dimension"; + assert dimension >= 0 : "PrimitiveType.createType(dim) : create type with negative dimension"; if (dimension == 0) { return this; } else { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index ad370b50..2dabbff0 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -79,11 +79,15 @@ public String toString() { @Override public boolean isAssignableFrom(Type type) { - if (type.isObject()) { - return typeMaker.isAssignable((ObjectType) this.type, (ObjectType) type); - } else if (type.isGeneric()) { + if (this.type.isObject()) { if (this.type.equals(TYPE_OBJECT)) { - return true; + if ((type.getDimension() > 0) || !type.isPrimitive()) { + return true; + } + } + + if (type.isObject()) { + return typeMaker.isAssignable((ObjectType) this.type, (ObjectType) type); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 17912868..35d03973 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -37,6 +37,7 @@ import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_STATIC; import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_SYNTHETIC; import static org.jd.core.v1.model.javasyntax.statement.ReturnStatement.RETURN; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; @@ -261,7 +262,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack bindings = new HashMap<>(); - if (rightTypeTypes.typeParameters.isList()) { + if (rightTypeTypes.typeParameters.isList() && objectType.getTypeArguments().isTypeArgumentList()) { Iterator iteratorTypeParameter = rightTypeTypes.typeParameters.iterator(); Iterator iteratorTypeArgument = objectType.getTypeArguments().getTypeArgumentList().iterator(); @@ -1213,7 +1213,7 @@ private Type loadFieldType(ObjectType objectType, String fieldName, String descr BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); HashMap bindings = new HashMap<>(); - if (typeTypes.typeParameters.isList()) { + if (typeTypes.typeParameters.isList() && typeArguments.isTypeArgumentList()) { Iterator iteratorTypeParameter = typeTypes.typeParameters.iterator(); Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); @@ -1303,7 +1303,7 @@ private MethodTypes loadMethodTypes(ObjectType objectType, String methodName, St HashMap bindings = new HashMap<>(); MethodTypes newMethodTypes = new MethodTypes(); - if (typeTypes.typeParameters.isList()) { + if (typeTypes.typeParameters.isList() && typeArguments.isTypeArgumentList()) { Iterator iteratorTypeParameter = typeTypes.typeParameters.iterator(); Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 7febc2d3..94910e37 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -18,6 +18,7 @@ import java.util.*; import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_STATIC; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; public class TypeParametersToTypeArgumentsBinder { protected PopulateBindingsWithTypeParameterVisitor populateBindingsWithTypeParameterVisitor = new PopulateBindingsWithTypeParameterVisitor(); @@ -75,7 +76,7 @@ public ClassFileConstructorInvocationExpression newConstructorInvocationExpressi TypeMaker.MethodTypes methodTypes, BaseExpression parameters) { BaseType parameterTypes = clone(methodTypes.parameterTypes); - Map bindings = createBindings(null, null, null, methodTypes.typeParameters, PrimitiveType.TYPE_VOID, null, parameterTypes, parameters); + Map bindings = createBindings(null, null, null, methodTypes.typeParameters, TYPE_OBJECT, null, parameterTypes, parameters); parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes); bindParameterTypesWithArgumentTypes(parameterTypes, parameters); @@ -99,7 +100,7 @@ public ClassFileSuperConstructorInvocationExpression newSuperConstructorInvocati BaseTypeArgument typeArguments = typeTypes.superType.getTypeArguments(); BaseTypeParameter methodTypeParameters = methodTypes.typeParameters; - bindings = createBindings(null, typeParameters, typeArguments, methodTypeParameters, PrimitiveType.TYPE_VOID, null, parameterTypes, parameters); + bindings = createBindings(null, typeParameters, typeArguments, methodTypeParameters, TYPE_OBJECT, null, parameterTypes, parameters); } } @@ -139,7 +140,7 @@ public FieldReferenceExpression newFieldReferenceExpression( BaseTypeParameter typeParameters = typeTypes.typeParameters; BaseTypeArgument typeArguments = expressionObjectType.getTypeArguments(); - bindings = createBindings(expression, typeParameters, typeArguments, null, PrimitiveType.TYPE_VOID, null, null, null); + bindings = createBindings(expression, typeParameters, typeArguments, null, TYPE_OBJECT, null, null, null); } type = (Type)bindParameterTypesWithArgumentTypes(bindings, type); @@ -303,7 +304,7 @@ protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileNewExpres protected void bindParameterTypesWithArgumentTypes(BaseType types, BaseExpression expressions) { if (types != null) { - if (types.isList()) { + if (types.isList() && expressions.isList()) { Iterator parameterTypesIterator = types.iterator(); Iterator parametersIterator = expressions.iterator(); @@ -344,7 +345,7 @@ protected Map createBindings( typeParameters.accept(populateBindingsWithTypeParameterVisitor); if (typeArguments != null) { - if (typeParameters.isList()) { + if (typeParameters.isList() && typeArguments.isTypeArgumentList()) { Iterator iteratorTypeParameter = typeParameters.iterator(); Iterator iteratorTypeArgument = typeArguments.getTypeArgumentList().iterator(); @@ -363,13 +364,13 @@ protected Map createBindings( methodTypeParameters.accept(populateBindingsWithTypeParameterVisitor); } - if ((returnType != PrimitiveType.TYPE_VOID) && (returnExpressionType != null)) { + if (!TYPE_OBJECT.equals(returnType) && (returnExpressionType != null)) { populateBindingsWithTypeArgumentVisitor.init(contextualTypeBounds, bindings, typeBounds, returnType); returnExpressionType.accept(populateBindingsWithTypeArgumentVisitor); } if (parameterTypes != null) { - if (parameterTypes.isList()) { + if (parameterTypes.isList() && parameters.isList()) { Iterator parameterTypesIterator = parameterTypes.iterator(); Iterator parametersIterator = parameters.iterator(); @@ -548,7 +549,7 @@ public void visit(NewExpression expression) { @Override public void visit(CastExpression expression) { - assert (type.getDimension() == expression.getType().getDimension()) : "TypeParametersToTypeArgumentsBinder.visit(CastExpression ce) : invalid array type"; + assert TYPE_OBJECT.equals(type) || (type.getDimension() == expression.getType().getDimension()) : "TypeParametersToTypeArgumentsBinder.visit(CastExpression ce) : invalid array type"; if (type.isObject()) { ObjectType objectType = (ObjectType)type; @@ -582,15 +583,19 @@ public void visit(CastExpression expression) { @Override public void visit(TernaryOperatorExpression expression) { - expression.setType(type); - bindParameterTypesWithArgumentTypes(type, expression.getExpressionTrue()); - bindParameterTypesWithArgumentTypes(type, expression.getExpressionFalse()); + Type t = type; + + expression.setType(t); + bindParameterTypesWithArgumentTypes(t, expression.getExpressionTrue()); + bindParameterTypesWithArgumentTypes(t, expression.getExpressionFalse()); } @Override public void visit(BinaryOperatorExpression expression) { - bindParameterTypesWithArgumentTypes(type, expression.getLeftExpression()); - bindParameterTypesWithArgumentTypes(type, expression.getRightExpression()); + Type t = type; + + bindParameterTypesWithArgumentTypes(t, expression.getLeftExpression()); + bindParameterTypesWithArgumentTypes(t, expression.getRightExpression()); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index f4778cdf..fcee997d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -122,11 +122,15 @@ public void visit(LocalVariableDeclarator declarator) { @Override public void visit(ArrayVariableInitializer declaration) { - Type t = type; + if (type.getDimension() == 0) { + acceptListDeclaration(declaration); + } else { + Type t = type; - type = type.createType(type.getDimension() - 1); - acceptListDeclaration(declaration); - type = t; + type = type.createType(type.getDimension() - 1); + acceptListDeclaration(declaration); + type = t; + } } @Override @@ -134,7 +138,12 @@ public void visit(ExpressionVariableInitializer declaration) { Expression expression = declaration.getExpression(); if (expression.getClass() == NewInitializedArray.class) { - ((NewInitializedArray)expression).getArrayInitializer().accept(this); + NewInitializedArray nia = (NewInitializedArray)expression; + Type t = type; + + type = nia.getType(); + nia.getArrayInitializer().accept(this); + type = t; } else { declaration.setExpression(updateExpression(type, expression)); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java index a63c2149..45697820 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java @@ -104,7 +104,8 @@ public void visit(GenericType type) { } else { typeArgumentToTypeVisitor.init(); ta.accept(typeArgumentToTypeVisitor); - result = typeArgumentToTypeVisitor.getType().createType(type.getDimension()); + Type t = typeArgumentToTypeVisitor.getType(); + result = t.createType(t.getDimension() + type.getDimension()); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java index 91087b09..9e97e35b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java @@ -10,9 +10,7 @@ import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import java.util.Map; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; @@ -63,7 +61,7 @@ public void visit(TypeArguments arguments) { } if (typeArgument == null) { - bindings.put(typeName, convertCurrentTypeArgument()); + bindings.put(typeName, checkTypeClassCheckDimensionAndReturnCurrentAsTypeArgument(type)); } else if (!current.equals(typeArgument)) { typeArgumentToTypeVisitor.init(); typeArgument.accept(typeArgumentToTypeVisitor); @@ -76,14 +74,14 @@ public void visit(TypeArguments arguments) { if (!t1.createType(0).equals(t2.createType(0))) { if (t1.isObject() && t2.isObject()) { ObjectType ot1 = (ObjectType)t1; - ObjectType ot2 = (ObjectType)t2; - - if (typeMaker.isAssignable(ot1, ot2)) { - bindings.put(typeName, typeArgument); - } else if (typeMaker.isAssignable(ot2, ot1)) { - bindings.put(typeName, convertCurrentTypeArgument()); - } else { - bindings.put(typeName, WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + ObjectType ot2 = (ObjectType)t2.createType(t2.getDimension() - type.getDimension()); + + if (!typeMaker.isAssignable(ot1, ot2)) { + if (typeMaker.isAssignable(ot2, ot1)) { + bindings.put(typeName, checkTypeClassCheckDimensionAndReturnCurrentAsTypeArgument(type)); + } else { + bindings.put(typeName, WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); + } } } } @@ -100,16 +98,25 @@ protected boolean equals(BaseType bt1, BaseType bt2) { } } - protected TypeArgument convertCurrentTypeArgument() { - if ((current != null) && (current.getClass() == ObjectType.class)) { - ObjectType ot = (ObjectType)current; + protected TypeArgument checkTypeClassCheckDimensionAndReturnCurrentAsTypeArgument(GenericType type) { + if (current != null) { + Class currentClass = current.getClass(); + + if (currentClass == ObjectType.class) { + ObjectType ot = (ObjectType) current; + + if ((ot.getTypeArguments() == null) && ot.getInternalName().equals(TYPE_CLASS.getInternalName())) { + return TYPE_CLASS_WILDCARD.createType(ot.getDimension()); + } - if ((ot.getTypeArguments() == null) && ot.getInternalName().equals(TYPE_CLASS.getInternalName())) { - return TYPE_CLASS_WILDCARD; + return ot.createType(ot.getDimension() - type.getDimension()); + } else if ((currentClass == InnerObjectType.class) || (currentClass == GenericType.class) || (currentClass == PrimitiveType.class)) { + Type t = (Type)current; + return t.createType(t.getDimension() - type.getDimension()); } } - return (TypeArgument)current; + return current.getTypeArgumentFirst(); } @Override From 83b3c1a13c2c7879733d8844e531c19f3b41cdff Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 2 Nov 2019 08:30:23 +0100 Subject: [PATCH 084/211] Fix error in operator precedence --- .../model/javasyntax/expression/BinaryOperatorExpression.java | 4 ++++ .../converter/classfiletojavasyntax/util/ByteCodeParser.java | 1 + 2 files changed, 5 insertions(+) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java index e01b3a5b..816cfe3a 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java @@ -61,6 +61,10 @@ public int getPriority() { return priority; } + public void setPriority(int priority) { + this.priority = priority; + } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 35d03973..6a0cca88 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1401,6 +1401,7 @@ private static boolean stackContainsFieldReference(DefaultStack stac private static Expression createAssignment(BinaryOperatorExpression boe, String operator) { boe.setOperator(operator); + boe.setPriority(16); return boe; } From 2503864357166f067e5ad93c03f683c2639f4093 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 2 Nov 2019 08:31:23 +0100 Subject: [PATCH 085/211] Fix error in enum declaration access flags --- .../visitor/UpdateJavaSyntaxTreeStep2Visitor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java index de6d50ac..e540b36c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateJavaSyntaxTreeStep2Visitor.java @@ -91,10 +91,10 @@ public void visit(InterfaceDeclaration declaration) { public void visit(EnumDeclaration declaration) { this.typeDeclaration = declaration; - // Remove 'static' and 'final' flags + // Remove 'static', 'final' and 'abstract' flags ClassFileEnumDeclaration cfed = (ClassFileEnumDeclaration)declaration; - cfed.setFlags(cfed.getFlags() ^ (Declaration.FLAG_STATIC|Declaration.FLAG_FINAL)); + cfed.setFlags(cfed.getFlags() & ~(Declaration.FLAG_STATIC|Declaration.FLAG_FINAL|Declaration.FLAG_ABSTRACT)); cfed.getBodyDeclaration().accept(this); initEnumVisitor.visit(cfed.getBodyDeclaration()); cfed.setConstants(initEnumVisitor.getConstants()); From 7fd25cc02e875be86ed79a5faf31f64cca7ac221 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 2 Nov 2019 08:32:06 +0100 Subject: [PATCH 086/211] Minor update --- src/main/java/org/jd/core/v1/util/DefaultList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/util/DefaultList.java b/src/main/java/org/jd/core/v1/util/DefaultList.java index aa9b30cb..48ca424c 100644 --- a/src/main/java/org/jd/core/v1/util/DefaultList.java +++ b/src/main/java/org/jd/core/v1/util/DefaultList.java @@ -14,7 +14,7 @@ @SuppressWarnings("unchecked") public class DefaultList extends ArrayList { - protected static EmptyList EMPTY_LIST = new EmptyList(); + protected static final EmptyList EMPTY_LIST = new EmptyList(); public DefaultList() {} From 0492ad63d1981f15e4128072520bbf08c3261579 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 2 Nov 2019 09:17:02 +0100 Subject: [PATCH 087/211] Fix error on integer constant definition --- .../UpdateIntegerConstantTypeVisitor.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index 8bf3d2c1..cae650d1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -99,16 +99,23 @@ public void visit(BinaryOperatorExpression expression) { Expression left = expression.getLeftExpression(); Expression right = expression.getRightExpression(); + Type leftType = left.getType(); + Type rightType = right.getType(); + switch (expression.getOperator()) { case "&": case "|": case "^": - left.accept(this); - right.accept(this); + Type type = PrimitiveTypeUtil.getCommonPrimitiveType((PrimitiveType)leftType, (PrimitiveType)rightType); + if (type == null) { + type = TYPE_INT; + } + expression.setLeftExpression(updateExpression(type, left)); + expression.setRightExpression(updateExpression(type, right)); break; case "=": left.accept(this); - expression.setRightExpression(updateExpression(left.getType(), right)); + expression.setRightExpression(updateExpression(leftType, right)); break; case ">": case ">=": @@ -116,14 +123,9 @@ public void visit(BinaryOperatorExpression expression) { case "<=": case "==": case "!=": - Type leftType = left.getType(); - Type rightType = right.getType(); - if ((leftType.getDimension() == 0) && (rightType.getDimension() == 0)) { if (leftType.isPrimitive()) { if (rightType.isPrimitive()) { - Type type; - if (leftType == rightType) { type = leftType; } else { @@ -132,7 +134,6 @@ public void visit(BinaryOperatorExpression expression) { type = TYPE_INT; } } - expression.setLeftExpression(updateExpression(type, left)); expression.setRightExpression(updateExpression(type, right)); } else { @@ -422,6 +423,9 @@ protected Expression updateExpression(Type type, Expression expression) { break; } break; + case FLAG_LONG: + ice.setType(TYPE_LONG); + break; } return expression; From 424d9b1c8584f8a1d50f9ff517c877886ecf909d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 3 Nov 2019 23:37:10 +0100 Subject: [PATCH 088/211] Fix error in instance field initialization --- .../visitor/InitInstanceFieldVisitor.java | 33 ++++++++++++++++--- .../UpdateIntegerConstantTypeVisitor.java | 3 +- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java index 75704e57..90dea711 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java @@ -7,7 +7,6 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; -import org.jd.core.v1.api.printer.Printer; import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; @@ -17,17 +16,21 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFieldDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import org.jd.core.v1.util.DefaultList; import java.util.*; +import static org.jd.core.v1.api.printer.Printer.UNKNOWN_LINE_NUMBER; + public class InitInstanceFieldVisitor extends AbstractJavaSyntaxVisitor { protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); protected HashMap fieldDeclarators = new HashMap<>(); protected DefaultList datas = new DefaultList<>(); protected DefaultList putFields = new DefaultList<>(); + protected int lineNumber = UNKNOWN_LINE_NUMBER; protected boolean containsLocalVariableReference; @Override @@ -89,7 +92,27 @@ public void visit(ConstructorDeclaration declaration) { datas.add(new Data(cfcd, statements, iterator.nextIndex())); if (datas.size() == 1) { - int firstLineNumber = superConstructorCall.getDescriptor().equals("()V") ? Printer.UNKNOWN_LINE_NUMBER : superConstructorCall.getLineNumber(); + int firstLineNumber = superConstructorCall.getLineNumber(); + + if (superConstructorCall.getDescriptor().equals("()V") && (firstLineNumber != UNKNOWN_LINE_NUMBER)) { + if ((lineNumber == UNKNOWN_LINE_NUMBER) || (lineNumber >= firstLineNumber)) { + ListIterator li = statements.listIterator(iterator.nextIndex()); + + while (li.hasNext()) { + searchFirstLineNumberVisitor.init(); + li.next().accept(searchFirstLineNumberVisitor); + int ln = searchFirstLineNumberVisitor.getLineNumber(); + if ((ln != UNKNOWN_LINE_NUMBER) && (ln < firstLineNumber)) { + break; + } + } + + if (!li.hasNext()) { + firstLineNumber = UNKNOWN_LINE_NUMBER; + } + } + } + initPutFields(internalTypeName, firstLineNumber, iterator); } else { filterPutFields(internalTypeName, iterator); @@ -99,7 +122,9 @@ public void visit(ConstructorDeclaration declaration) { } @Override - public void visit(MethodDeclaration declaration) {} + public void visit(MethodDeclaration declaration) { + lineNumber = ((ClassFileMethodDeclaration)declaration).getFirstLineNumber(); + } @Override public void visit(NewExpression expression) { @@ -190,7 +215,7 @@ protected void initPutFields(String internalTypeName, int firstLineNumber, ListI int lastLineNumber; if (expression == null) { - lastLineNumber = (firstLineNumber == Printer.UNKNOWN_LINE_NUMBER) ? Printer.UNKNOWN_LINE_NUMBER : firstLineNumber+1; + lastLineNumber = (firstLineNumber == UNKNOWN_LINE_NUMBER) ? UNKNOWN_LINE_NUMBER : firstLineNumber+1; } else { lastLineNumber = expression.getLineNumber(); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index cae650d1..ce884ef0 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -424,8 +424,7 @@ protected Expression updateExpression(Type type, Expression expression) { } break; case FLAG_LONG: - ice.setType(TYPE_LONG); - break; + return new LongConstantExpression(ice.getLineNumber(), ice.getValue()); } return expression; From 34ea0c5ab9173b3ff1755e271a759aa57cca120d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 5 Nov 2019 19:57:50 +0100 Subject: [PATCH 089/211] Fix error in instance field initialization --- .../visitor/InitInstanceFieldVisitor.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java index 90dea711..718a717c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java @@ -94,20 +94,15 @@ public void visit(ConstructorDeclaration declaration) { if (datas.size() == 1) { int firstLineNumber = superConstructorCall.getLineNumber(); - if (superConstructorCall.getDescriptor().equals("()V") && (firstLineNumber != UNKNOWN_LINE_NUMBER)) { + if (superConstructorCall.getDescriptor().equals("()V") && (firstLineNumber != UNKNOWN_LINE_NUMBER) && iterator.hasNext()) { if ((lineNumber == UNKNOWN_LINE_NUMBER) || (lineNumber >= firstLineNumber)) { - ListIterator li = statements.listIterator(iterator.nextIndex()); - - while (li.hasNext()) { - searchFirstLineNumberVisitor.init(); - li.next().accept(searchFirstLineNumberVisitor); - int ln = searchFirstLineNumberVisitor.getLineNumber(); - if ((ln != UNKNOWN_LINE_NUMBER) && (ln < firstLineNumber)) { - break; - } - } + searchFirstLineNumberVisitor.init(); + iterator.next().accept(searchFirstLineNumberVisitor); + iterator.previous(); + + int ln = searchFirstLineNumberVisitor.getLineNumber(); - if (!li.hasNext()) { + if ((ln != UNKNOWN_LINE_NUMBER) && (ln >= firstLineNumber)) { firstLineNumber = UNKNOWN_LINE_NUMBER; } } From 1a8247021be20a554c6fd440a7c1cd259f9bc836 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 5 Nov 2019 19:58:31 +0100 Subject: [PATCH 090/211] Update build file --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index 5f441c7a..da658e52 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,9 @@ apply plugin: 'com.jfrog.bintray' dependencies { testCompile 'junit:junit:4.12' + testCompile 'org.apache.commons:commons-lang3:3.9' testCompile 'org.apache.commons:commons-collections4:4.1' + testCompile 'commons-codec:commons-codec:1.13' } version='1.1.1' From 9da4f4b77fabc1ab48a155f6e0c21fd3e9416cb7 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 5 Nov 2019 20:04:20 +0100 Subject: [PATCH 091/211] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 182feded..8de12f82 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,10 @@ generate _"build/libs/jd-core-x.y.z.jar"_ ## How to use JD-Core ? 1. Implement the -_[jd.core.loader.Loader](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/v1/api/loader/Loader.java)_ +_[org.jd.core.loader.Loader](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/v1/api/loader/Loader.java)_ interface, 2. Implement the -_[jd.core.printer.Printer](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/v1/api/printer/Printer.java)_ +_[org.jd.core.printer.Printer](https://github.com/java-decompiler/jd-core/blob/master/src/main/java/org/jd/core/v1/api/printer/Printer.java)_ interface, 3. And call the method _"decompile(loader, printer, internalTypeName);"_ From b804323811e40ec2d0c24cf7d9e18e5930a270c3 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 17 Nov 2019 16:26:30 +0100 Subject: [PATCH 092/211] Fix bug with try-with-resources --- .../visitor/RemoveFinallyStatementsVisitor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java index 1ab3ccc8..ac8d7216 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java @@ -50,6 +50,8 @@ public void visit(Statements statements) { } else if (lastStatementClass == ThrowStatement.class) { statementCountToRemove = 0; i--; + } else if ((lastStatementClass == ContinueStatement.class) ||(lastStatementClass == BreakStatement.class)) { + i--; } else { WhileStatement whileStatement = getInfiniteWhileStatement(lastStatement); From b9c0481cec3676ebefc86583926ab56d73792d00 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 17 Nov 2019 17:24:46 +0100 Subject: [PATCH 093/211] Fix error in instance field initializations --- .../visitor/InitInstanceFieldVisitor.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java index 718a717c..fc659d4c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java @@ -24,6 +24,7 @@ import java.util.*; import static org.jd.core.v1.api.printer.Printer.UNKNOWN_LINE_NUMBER; +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_SYNTHETIC; public class InitInstanceFieldVisitor extends AbstractJavaSyntaxVisitor { protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); @@ -92,18 +93,24 @@ public void visit(ConstructorDeclaration declaration) { datas.add(new Data(cfcd, statements, iterator.nextIndex())); if (datas.size() == 1) { - int firstLineNumber = superConstructorCall.getLineNumber(); + int firstLineNumber; - if (superConstructorCall.getDescriptor().equals("()V") && (firstLineNumber != UNKNOWN_LINE_NUMBER) && iterator.hasNext()) { - if ((lineNumber == UNKNOWN_LINE_NUMBER) || (lineNumber >= firstLineNumber)) { - searchFirstLineNumberVisitor.init(); - iterator.next().accept(searchFirstLineNumberVisitor); - iterator.previous(); + if ((cfcd.getFlags() & FLAG_SYNTHETIC) != 0) { + firstLineNumber = UNKNOWN_LINE_NUMBER; + } else { + firstLineNumber = superConstructorCall.getLineNumber(); - int ln = searchFirstLineNumberVisitor.getLineNumber(); + if (superConstructorCall.getDescriptor().equals("()V") && (firstLineNumber != UNKNOWN_LINE_NUMBER) && iterator.hasNext()) { + if ((lineNumber == UNKNOWN_LINE_NUMBER) || (lineNumber >= firstLineNumber)) { + searchFirstLineNumberVisitor.init(); + iterator.next().accept(searchFirstLineNumberVisitor); + iterator.previous(); - if ((ln != UNKNOWN_LINE_NUMBER) && (ln >= firstLineNumber)) { - firstLineNumber = UNKNOWN_LINE_NUMBER; + int ln = searchFirstLineNumberVisitor.getLineNumber(); + + if ((ln != UNKNOWN_LINE_NUMBER) && (ln >= firstLineNumber)) { + firstLineNumber = UNKNOWN_LINE_NUMBER; + } } } } From a52fe37d2d0f5e275a98df426b8b9763614e6b4f Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 17 Nov 2019 17:25:22 +0100 Subject: [PATCH 094/211] Update tests --- .../org/jd/core/v1/JarFileToJavaSourceTest.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 531b253d..225a25d2 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -36,12 +36,25 @@ public class JarFileToJavaSourceTest extends TestCase { protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); protected WriteTokenProcessor writer = new WriteTokenProcessor(); + // TODO In progress +// @Test +// public void testCommonsLang3() throws Exception { +// // Decompile and recompile 'commons-lang3-3.9.jar' +// test(org.apache.commons.lang3.JavaVersion.class); +// } + @Test public void testCommonsCollections4() throws Exception { - // Test 'commons-collections4-4.1.jar' + // Decompile and recompile 'commons-collections4-4.1.jar' test(org.apache.commons.collections4.CollectionUtils.class); } + @Test + public void testCommonsCodec() throws Exception { + // Decompile and recompile 'commons-codec-1.13.jar' + test(org.apache.commons.codec.Charsets.class); + } + protected void test(Class clazz) throws Exception { test(new FileInputStream(Paths.get(clazz.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile())); } @@ -72,6 +85,8 @@ protected void test(InputStream inputStream) throws Exception { if (path.endsWith(".class") && (path.indexOf('$') == -1)) { String internalTypeName = path.substring(0, path.length() - 6); // 6 = ".class".length() + // TODO DEBUG if (!internalTypeName.endsWith("/Rule")) continue; + message.setHeader("mainInternalTypeName", internalTypeName); printer.init(); From 8efb011f64ea5519c8687b1dda6ca8d775e154ef Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 17 Nov 2019 17:29:06 +0100 Subject: [PATCH 095/211] Update version to 1.1.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index da658e52..ea554a29 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile 'commons-codec:commons-codec:1.13' } -version='1.1.1' +version='1.1.2' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From f1a57ed59e295516448694b8aad1c1d7504008ee Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 20 Nov 2019 19:05:35 +0100 Subject: [PATCH 096/211] Works on try-catch-finally statements --- .../util/ControlFlowGraphReducer.java | 73 ++++++++++++------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index cdf0251c..2a1390ee 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -759,6 +759,11 @@ protected static boolean reduceTryDeclaration(BitSet visited, BasicBlock basicBl exceptionHandler.setBasicBlock(END); } else { int offset = (bb.getFromOffset() == maxOffset) ? end.getFromOffset() : maxOffset; + + if (offset == 0) { + offset = Integer.MAX_VALUE; + } + BasicBlock last = updateBlock(bb, end, offset); if (toOffset < last.getToOffset()) { @@ -847,11 +852,17 @@ protected static BasicBlock searchJsrTarget(BasicBlock basicBlock, BitSet jsrTar } protected static BasicBlock searchEndBlock(BasicBlock basicBlock, int maxOffset) { + BasicBlock end = null; BasicBlock last = splitSequence(basicBlock.getNext(), maxOffset); - BasicBlock next = last.getNext(); - if (!next.matchType(TYPE_END|TYPE_LOOP_START|TYPE_LOOP_CONTINUE|TYPE_LOOP_END|TYPE_JUMP) && ((next.getFromOffset() >= maxOffset) || (next.getToOffset() < basicBlock.getFromOffset()))) { - return next; + if (!last.matchType(GROUP_END)) { + BasicBlock next = last.getNext(); + + if ((next.getFromOffset() >= maxOffset) || (!next.matchType(TYPE_END|TYPE_RETURN|TYPE_SWITCH_BREAK|TYPE_LOOP_START|TYPE_LOOP_CONTINUE|TYPE_LOOP_END) && (next.getToOffset() < basicBlock.getFromOffset()))) { + return next; + } + + end = next; } for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { @@ -859,19 +870,28 @@ protected static BasicBlock searchEndBlock(BasicBlock basicBlock, int maxOffset) if (bb.getFromOffset() < maxOffset) { last = splitSequence(bb, maxOffset); - next = last.getNext(); - if (!next.matchType(TYPE_END|TYPE_LOOP_START|TYPE_LOOP_CONTINUE|TYPE_LOOP_END|TYPE_JUMP) && ((next.getFromOffset() >= maxOffset) || (next.getToOffset() < basicBlock.getFromOffset()))) { - return next; + if (!last.matchType(GROUP_END)) { + BasicBlock next = last.getNext(); + + if ((next.getFromOffset() >= maxOffset) || (!next.matchType(TYPE_END | TYPE_RETURN | TYPE_SWITCH_BREAK | TYPE_LOOP_START | TYPE_LOOP_CONTINUE | TYPE_LOOP_END) && (next.getToOffset() < basicBlock.getFromOffset()))) { + return next; + } + + if (end == null) { + end = next; + } else if (end != next) { + end = END; + } } } else { // Last handler block ControlFlowGraph cfg = bb.getControlFlowGraph(); int lineNumber = cfg.getLineNumber(bb.getFromOffset()); WatchDog watchdog = new WatchDog(); + BasicBlock next = bb.getNext(); last = bb; - next = bb.getNext(); while ((last != next) && last.matchType(GROUP_SINGLE_SUCCESSOR) && (next.getPredecessors().size() == 1) && (lineNumber <= cfg.getLineNumber(next.getFromOffset()))) { watchdog.check(next, next.getNext()); @@ -879,12 +899,22 @@ protected static BasicBlock searchEndBlock(BasicBlock basicBlock, int maxOffset) next = next.getNext(); } - if ((last != next) && ((next.getPredecessors().size() > 1) || !next.matchType(GROUP_END))) { - return next; + if (!last.matchType(GROUP_END)) { + if ((last != next) && ((next.getPredecessors().size() > 1) || !next.matchType(GROUP_END))) { + return next; + } + + if ((end != next) && (exceptionHandler.getInternalThrowableName() != null)) { + end = END; + } } } } + if ((end != null) && end.matchType(TYPE_SWITCH_BREAK|TYPE_LOOP_START|TYPE_LOOP_CONTINUE|TYPE_LOOP_END)) { + return end; + } + return END; } @@ -920,24 +950,17 @@ protected static BasicBlock splitSequence(BasicBlock basicBlock, int maxOffset) protected static BasicBlock updateBlock(BasicBlock basicBlock, BasicBlock end, int maxOffset) { WatchDog watchdog = new WatchDog(); - if (end == END) { - while (basicBlock.matchType(GROUP_SINGLE_SUCCESSOR)) { - watchdog.check(basicBlock, basicBlock.getNext()); - basicBlock = basicBlock.getNext(); - } - } else { - while (basicBlock.matchType(GROUP_SINGLE_SUCCESSOR)) { - watchdog.check(basicBlock, basicBlock.getNext()); - BasicBlock next = basicBlock.getNext(); - - if ((next == end) || (next.getFromOffset() > maxOffset)) { - next.getPredecessors().remove(basicBlock); - basicBlock.setNext(END); - break; - } + while (basicBlock.matchType(GROUP_SINGLE_SUCCESSOR)) { + watchdog.check(basicBlock, basicBlock.getNext()); + BasicBlock next = basicBlock.getNext(); - basicBlock = next; + if ((next == end) || (next.getFromOffset() > maxOffset)) { + next.getPredecessors().remove(basicBlock); + basicBlock.setNext(END); + break; } + + basicBlock = next; } return basicBlock; From bcf976b2e3184e0681b9f7a63c727a09ad3e9c50 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 20 Nov 2019 23:06:12 +0100 Subject: [PATCH 097/211] Fix bug in enum constant declarations --- .../declaration/ClassFileEnumDeclaration.java | 5 +-- .../visitor/InitEnumVisitor.java | 19 ++++++++-- .../visitor/InitStaticFieldVisitor.java | 35 +++++++++---------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java index ed3c282d..d52f82ad 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java @@ -7,6 +7,7 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration; +import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; import org.jd.core.v1.model.javasyntax.declaration.EnumDeclaration; import org.jd.core.v1.model.javasyntax.expression.BaseExpression; import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; @@ -43,8 +44,8 @@ public String toString() { public static class ClassFileConstant extends Constant { protected int index; - public ClassFileConstant(int lineNumber, String name, int index, BaseExpression arguments) { - super(lineNumber, name, arguments); + public ClassFileConstant(int lineNumber, String name, int index, BaseExpression arguments, BodyDeclaration bodyDeclaration) { + super(lineNumber, name, arguments, bodyDeclaration); this.index = index; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java index 494bd455..e6ad6f31 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java @@ -20,6 +20,8 @@ public class InitEnumVisitor extends AbstractJavaSyntaxVisitor { + protected ClassFileBodyDeclaration bodyDeclaration = null; + protected BodyDeclaration constantBodyDeclaration = null; protected DefaultList constants = new DefaultList<>(); protected int lineNumber; protected int index; @@ -36,10 +38,13 @@ public DefaultList getConstants() { @Override public void visit(BodyDeclaration declaration) { - ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; + ClassFileBodyDeclaration bd = bodyDeclaration; + + bodyDeclaration = (ClassFileBodyDeclaration)declaration; constants.clear(); safeAcceptListDeclaration(bodyDeclaration.getFieldDeclarations()); safeAcceptListDeclaration(bodyDeclaration.getMethodDeclarations()); + bodyDeclaration = bd; } @Override @@ -89,8 +94,9 @@ public void visit(FieldDeclaration declaration) { @Override public void visit(FieldDeclarator declaration) { + constantBodyDeclaration = null; safeAccept(declaration.getVariableInitializer()); - constants.add(new ClassFileEnumDeclaration.ClassFileConstant(lineNumber, declaration.getName(), index, arguments)); + constants.add(new ClassFileEnumDeclaration.ClassFileConstant(lineNumber, declaration.getName(), index, arguments, constantBodyDeclaration)); } @Override @@ -115,6 +121,15 @@ public void visit(NewExpression expression) { parameters.subList(0, 2).clear(); arguments = parameters; } + + String enumInternalTypeName = expression.getObjectType().getInternalName(); + + if (!enumInternalTypeName.equals(bodyDeclaration.getInternalTypeName())) { + ClassFileMemberDeclaration md = bodyDeclaration.getInnerTypeDeclaration(enumInternalTypeName); + if (md != null) { + constantBodyDeclaration = ((ClassFileEnumDeclaration)md).getBodyDeclaration(); + } + } } protected static class EnumConstantComparator implements Comparator { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java index 75509569..e301f5b3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java @@ -12,6 +12,7 @@ import org.jd.core.v1.model.javasyntax.expression.BinaryOperatorExpression; import org.jd.core.v1.model.javasyntax.expression.Expression; import org.jd.core.v1.model.javasyntax.expression.FieldReferenceExpression; +import org.jd.core.v1.model.javasyntax.statement.BaseStatement; import org.jd.core.v1.model.javasyntax.statement.ExpressionStatement; import org.jd.core.v1.model.javasyntax.statement.Statement; import org.jd.core.v1.model.javasyntax.type.PrimitiveType; @@ -84,27 +85,25 @@ public void visit(MethodDeclaration declaration) {} public void visit(StaticInitializerDeclaration declaration) { staticDeclaration = (ClassFileStaticInitializerDeclaration) declaration; - if (!staticDeclaration.getStatements().isList()) { - return; - } - - DefaultList statements = staticDeclaration.getStatements().getList(); + BaseStatement statements = staticDeclaration.getStatements(); - if ((statements != null) && !statements.isEmpty()) { - Statement statement = statements.getFirst(); + if ((statements != null) && (statements.size() > 0)) { + if (statements.isList()) { + Statement statement = statements.getFirst(); - if (statement.getClass() == ExpressionStatement.class) { - ExpressionStatement cdes = (ExpressionStatement) statement; + if ((statement.getClass() == ExpressionStatement.class)) { + ExpressionStatement cdes = (ExpressionStatement) statement; - if (cdes.getExpression().getClass() == BinaryOperatorExpression.class) { - BinaryOperatorExpression cfboe = (BinaryOperatorExpression) cdes.getExpression(); + if (cdes.getExpression().getClass() == BinaryOperatorExpression.class) { + BinaryOperatorExpression cfboe = (BinaryOperatorExpression) cdes.getExpression(); - if (cfboe.getLeftExpression().getClass() == FieldReferenceExpression.class) { - FieldReferenceExpression fre = (FieldReferenceExpression) cfboe.getLeftExpression(); + if (cfboe.getLeftExpression().getClass() == FieldReferenceExpression.class) { + FieldReferenceExpression fre = (FieldReferenceExpression) cfboe.getLeftExpression(); - if ((fre.getType() == PrimitiveType.TYPE_BOOLEAN) && fre.getInternalTypeName().equals(internalTypeName) && fre.getName().equals("$assertionsDisabled")) { - // Remove assert initialization statement - statements.remove(0); + if ((fre.getType() == PrimitiveType.TYPE_BOOLEAN) && fre.getInternalTypeName().equals(internalTypeName) && fre.getName().equals("$assertionsDisabled")) { + // Remove assert initialization statement + statements.getList().removeFirst(); + } } } } @@ -114,7 +113,7 @@ public void visit(StaticInitializerDeclaration declaration) { Iterator fieldDeclaratorIterator = fields.iterator(); while (statementIterator.hasNext()) { - statement = statementIterator.next(); + Statement statement = statementIterator.next(); if (statement.getClass() != ExpressionStatement.class) { break; @@ -161,7 +160,7 @@ public void visit(StaticInitializerDeclaration declaration) { } } - if (statements.isEmpty()) { + if (statements.size() == 0) { staticDeclaration.setStatements(null); staticDeclaration.setFirstLineNumber(0); } else { From 0f94f879696b4d3788619626f49157c0ffabd8bc Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 21 Nov 2019 20:12:24 +0100 Subject: [PATCH 098/211] Fix problem in bridged field instance references --- .../ObjectTypeReferenceExpression.java | 4 ++++ .../util/ByteCodeParser.java | 4 +++- .../visitor/UpdateBridgeMethodVisitor.java | 18 ++++++++++++++---- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java index 09abe476..247fa0b5 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java @@ -55,6 +55,10 @@ public boolean isExplicit() { return explicit; } + public void setExplicit(boolean explicit) { + this.explicit = explicit; + } + @Override public int getPriority() { return 0; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 6a0cca88..cfce5e3c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -7,6 +7,7 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; +import org.jd.core.v1.api.printer.Printer; import org.jd.core.v1.model.classfile.ClassFile; import org.jd.core.v1.model.classfile.ConstantPool; import org.jd.core.v1.model.classfile.Method; @@ -76,6 +77,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStackgetAttribute("Code").getCode(); + boolean syntheticFlag = (method.getAccessFlags() & FLAG_SYNTHETIC) != 0; Expression indexRef, arrayRef, valueRef, expression1, expression2, expression3; Type type1, type2, type3; @@ -88,7 +90,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack map = null; From 1e34e52cdfbeac47839fad3243a3c5a148a70bed Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 23 Nov 2019 13:51:18 +0100 Subject: [PATCH 099/211] Fix syntax errors in decompiled sources --- .../model/localvariable/Frame.java | 20 +++++++++++-------- .../util/LocalVariableMaker.java | 19 ++++++------------ .../visitor/UpdateBridgeMethodVisitor.java | 5 +++-- .../jd/core/v1/ClassFileToJavaSourceTest.java | 6 +++--- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 9dd1fd57..c7c5cec8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -196,16 +196,19 @@ public void createNames(HashSet parentNames) { AbstractLocalVariable lv = localVariableArray[i]; while (lv != null) { - if (lv.name == null) { - if (types.containsKey(lv.getType())) { - // Non unique type - types.put(lv.getType(), Boolean.TRUE); + if (types.containsKey(lv.getType())) { + // Non unique type + types.put(lv.getType(), Boolean.TRUE); + } else { + // Unique type + types.put(lv.getType(), Boolean.FALSE); + } + if (lv.name != null) { + if (names.contains(lv.name)) { + lv.name = null; } else { - // Unique type - types.put(lv.getType(), Boolean.FALSE); + names.add(lv.name); } - } else { - names.add(lv.name); } assert lv != lv.getNext(); lv = lv.getNext(); @@ -318,6 +321,7 @@ protected boolean createInlineDeclarations() { for (AbstractLocalVariable lv : sorted) { // Add declaration before current statement iterator.add(new LocalVariableDeclarationStatement(lv.getType(), new LocalVariableDeclarator(lv.getName()))); + lv.setDeclared(true); undeclaredLocalVariables.remove(lv); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 668e09b0..38cfdc34 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -59,8 +59,6 @@ public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDecla if (descriptor.charAt(descriptor.length() - 1) == ';') { typeMaker.makeFromDescriptor(descriptor).accept(populateBlackListNamesVisitor); } - - blackListNames.add(field.getName()); } } @@ -96,7 +94,6 @@ public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDecla if (localVariableSet.root(0) == null) { // Local variable missing localVariableSet.add(0, new ObjectLocalVariable(typeMaker, 0, 0, typeMaker.makeFromInternalTypeName(classFile.getInternalTypeName()), "this")); - blackListNames.add("this"); } firstVariableIndex = 1; } @@ -106,23 +103,20 @@ public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDecla if (localVariableSet.root(1) == null) { // Local variable missing localVariableSet.add(1, new ObjectLocalVariable(typeMaker, 1, 0, ObjectType.TYPE_STRING, "this$enum$name")); - blackListNames.add("this$enum$name"); } if (localVariableSet.root(2) == null) { // Local variable missing localVariableSet.add(2, new PrimitiveLocalVariable(2, 0, PrimitiveType.TYPE_INT, "this$enum$index")); - blackListNames.add("this$enum$index"); } } else if ((classFile.getOuterClassFile() != null) && ((classFile.getAccessFlags() & FLAG_STATIC) == 0)) { if (localVariableSet.root(1) == null) { // Local variable missing localVariableSet.add(1, new ObjectLocalVariable(typeMaker, 1, 0, typeMaker.makeFromInternalTypeName(classFile.getOuterClassFile().getInternalTypeName()), "this$0")); - blackListNames.add("this$0"); } } } - if ((parameterTypes != null) && (parameterTypes != null)) { + if (parameterTypes != null) { int lastParameterIndex = parameterTypes.size() - 1; boolean varargs = ((method.getAccessFlags() & FLAG_VARARGS) != 0); @@ -199,7 +193,6 @@ protected void initLocalVariablesFromAttributes(Method method) { } localVariableSet.add(index, lv); - blackListNames.add(name); names.add(name); } } @@ -272,13 +265,13 @@ protected void initLocalVariablesFromParameterTypes(ClassFile classFile, BaseTyp String name = sb.toString(); - while (blackListNames.contains(name)) { + while (names.contains(name)) { sb.setLength(length); sb.append(counter++); name = sb.toString(); } - blackListNames.add(name); + names.add(name); createParameterVisitor.init(variableIndex, name); type.accept(createParameterVisitor); @@ -326,11 +319,11 @@ protected AbstractLocalVariable searchLocalVariable(int index, int offset) { } else { AbstractLocalVariable lv2 = currentFrame.getLocalVariable(index); - if ((lv2 != null) && (lv.getFromOffset() < lv2.getFromOffset())) { + if ((lv2 != null) && ((lv.getName() == null) ? (lv2.getName() == null) : lv.getName().equals(lv2.getName())) && lv.getType().equals(lv2.getType())) { lv = lv2; - } else { - localVariableSet.remove(index, offset); } + + localVariableSet.remove(index, offset); } return lv; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java index 548411ec..9998bc5e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateBridgeMethodVisitor.java @@ -181,9 +181,10 @@ protected Expression updateExpression(Expression expression) { protected static FieldReferenceExpression getFieldReferenceExpression(Expression expression) { FieldReferenceExpression fre = (FieldReferenceExpression) expression; + Expression freExpression = fre.getExpression(); - if (fre.getExpression().getClass() == ObjectTypeReferenceExpression.class) { - ((ObjectTypeReferenceExpression)fre.getExpression()).setExplicit(true); + if ((freExpression != null) && (freExpression.getClass() == ObjectTypeReferenceExpression.class)) { + ((ObjectTypeReferenceExpression)freExpression).setExplicit(true); } return fre; diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index a512b2df..a348db84 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -713,7 +713,7 @@ public void testJdk170For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 245 */", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); assertTrue(source.matches(PatternMaker.make("/* 253: 0 */", "while (true) {"))); assertTrue(source.matches(PatternMaker.make(": 264 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); assertTrue(source.matches(PatternMaker.make(": 389 */", "for (String s : array)"))); assertTrue(source.matches(PatternMaker.make(": 403 */", "for (String s : list)"))); assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); @@ -839,7 +839,7 @@ public void testJdk160For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 16 */", "for (int i = 0; i < 10; i++)"))); assertTrue(source.matches(PatternMaker.make(": 84 */", "while (i < 10)"))); assertTrue(source.matches(PatternMaker.make(": 269 */", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int j : new int[] { 4 })"))); assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do {"))); assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); @@ -882,7 +882,7 @@ public void testIbmJ9For() throws Exception { // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 84 */", "while (i < 10)"))); assertTrue(source.matches(PatternMaker.make(": 269 */", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int j : new int[] { 4 })"))); assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do"))); assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); From 56f4bf10eabb8645d3ac27a9395abd3cb831be12 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 23 Nov 2019 14:28:34 +0100 Subject: [PATCH 100/211] Fix error with Float.NaN and Double.NaN --- .../converter/classfiletojavasyntax/util/ByteCodeParser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index cfce5e3c..c541ede5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1006,7 +1006,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in stack.push(new FieldReferenceExpression(lineNumber, TYPE_FLOAT, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_FLOAT), "java/lang/Float", "NEGATIVE_INFINITY", "F")); } else if (f == Float.POSITIVE_INFINITY) { stack.push(new FieldReferenceExpression(lineNumber, TYPE_FLOAT, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_FLOAT), "java/lang/Float", "POSITIVE_INFINITY", "F")); - } else if (f == Float.NaN) { + } else if (Float.isNaN(f)) { stack.push(new FieldReferenceExpression(lineNumber, TYPE_FLOAT, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_FLOAT), "java/lang/Float", "NaN", "F")); } else { stack.push(new FloatConstantExpression(lineNumber, f)); @@ -1043,7 +1043,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in stack.push(new FieldReferenceExpression(lineNumber, TYPE_DOUBLE, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_DOUBLE), "java/lang/Double", "NEGATIVE_INFINITY", "D")); } else if (d == Double.POSITIVE_INFINITY) { stack.push(new FieldReferenceExpression(lineNumber, TYPE_DOUBLE, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_DOUBLE), "java/lang/Double", "POSITIVE_INFINITY", "D")); - } else if (d == Double.NaN) { + } else if (Double.isNaN(d)) { stack.push(new FieldReferenceExpression(lineNumber, TYPE_DOUBLE, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_DOUBLE), "java/lang/Double", "NaN", "D")); } else if (d == Math.E) { stack.push(new FieldReferenceExpression(lineNumber, TYPE_DOUBLE, new ObjectTypeReferenceExpression(lineNumber, ObjectType.TYPE_MATH), "java/lang/Math", "E", "D")); From e8462bd0e5c803fb1c68b0e3dbebd48d0ed25948 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 27 Nov 2019 13:43:57 +0100 Subject: [PATCH 101/211] Fix syntax errors in decompiled sources --- .../model/localvariable/Frame.java | 8 ++++-- .../cfg/ControlFlowGraphPlantUMLWriter.java | 26 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index c7c5cec8..d2079502 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -93,8 +93,12 @@ public void mergeLocalVariable(LocalVariableMaker localVariableMaker, AbstractLo alvToMerge = null; } - if ((alvToMerge != null) && (alvToMerge.getClass() != lv.getClass())) { - alvToMerge = null; + if (alvToMerge != null) { + if (!lv.isAssignableFrom(alvToMerge) && !alvToMerge.isAssignableFrom(lv)) { + alvToMerge = null; + } else if ((lv.getName() != null) && (alvToMerge.getName() != null) && !lv.getName().equals(alvToMerge.getName())) { + alvToMerge = null; + } } if (alvToMerge == null) { diff --git a/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java b/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java index 0cf8ac0b..5597f48b 100644 --- a/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java +++ b/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java @@ -28,6 +28,8 @@ * http://plantuml.com/plantuml */ public class ControlFlowGraphPlantUMLWriter { + protected static final int MAX_OFFSET = Integer.MAX_VALUE; + //protected static final String PLANTUML_URL_PREFIX = "http://plantuml.com/plantuml/png/"; protected static final String PLANTUML_URL_PREFIX = "http://plantuml.com/plantuml/svg/"; protected static final char[] PLANTUML_ENCODE_6_BIT = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".toCharArray(); @@ -82,11 +84,13 @@ public static String write(ControlFlowGraph cfg) { Method method = cfg.getMethod(); - for (BasicBlock basicBlock : list) + for (BasicBlock basicBlock : list) { writeState(sb, method, basicBlock); + } - for (BasicBlock basicBlock : list) + for (BasicBlock basicBlock : list) { writeLink(sb, basicBlock); + } return sb.toString(); } @@ -112,8 +116,9 @@ protected static void search(HashSet set, BasicBlock basicBlock) { case TYPE_SWITCH: search(set, basicBlock.getNext()); case TYPE_SWITCH_DECLARATION: - for (SwitchCase switchCase : basicBlock.getSwitchCases()) + for (SwitchCase switchCase : basicBlock.getSwitchCases()) { search(set, switchCase.getBasicBlock()); + } break; case TYPE_TRY: case TYPE_TRY_JSR: @@ -121,8 +126,9 @@ protected static void search(HashSet set, BasicBlock basicBlock) { search(set, basicBlock.getSub1()); case TYPE_TRY_DECLARATION: search(set, basicBlock.getNext()); - for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) + for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { search(set, exceptionHandler.getBasicBlock()); + } break; case TYPE_IF: search(set, basicBlock.getCondition()); @@ -144,6 +150,10 @@ protected static void search(HashSet set, BasicBlock basicBlock) { } protected static void writeState(StringBuilder sb, Method method, BasicBlock basicBlock) { + if (basicBlock.getFromOffset() > MAX_OFFSET) { + return; + } + String id = getStateId(basicBlock); switch (basicBlock.getType()) { @@ -300,6 +310,10 @@ protected static void writeStateEnd(StringBuilder sb, String id, BasicBlock basi } protected static void writeLink(StringBuilder sb, BasicBlock basicBlock) { + if (basicBlock.getFromOffset() > MAX_OFFSET) { + return; + } + String id = getStateId(basicBlock); switch (basicBlock.getType()) { @@ -399,6 +413,10 @@ protected static void writeLink(StringBuilder sb, BasicBlock basicBlock) { } protected static void writeLink(StringBuilder sb, String fromId, BasicBlock to, String label) { + if (to.getFromOffset() > MAX_OFFSET) { + return; + } + if (to == SWITCH_BREAK) { sb.append("state \"SWITCH_BREAK\" as switch_break_").append(fromId).append('\n'); sb.append(fromId).append(" --> switch_break_").append(fromId).append(" : ").append(label).append('\n'); From 30c89a4dce7f22908a0195c9bb98e5e586b66cf0 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 27 Nov 2019 17:32:13 +0100 Subject: [PATCH 102/211] Fix syntax errors in decompiled sources --- .../util/ByteCodeParser.java | 3 +- .../util/ControlFlowGraphLoopReducer.java | 105 +++++++++++------- .../util/ControlFlowGraphReducer.java | 2 +- 3 files changed, 68 insertions(+), 42 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index c541ede5..2885f922 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -7,7 +7,6 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.util; -import org.jd.core.v1.api.printer.Printer; import org.jd.core.v1.model.classfile.ClassFile; import org.jd.core.v1.model.classfile.ConstantPool; import org.jd.core.v1.model.classfile.Method; @@ -90,7 +89,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack list, BasicBlock start, BitSet s if (end == END) { // Not found, check all member blocks - for (BasicBlock member : members) { - switch (member.getType()) { - case TYPE_CONDITIONAL_BRANCH: - BasicBlock bb = member.getBranch(); - if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { - end = bb; - maxOffset = bb.getFromOffset(); - break; - } - case TYPE_STATEMENTS: - case TYPE_GOTO: - bb = member.getNext(); - if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { - end = bb; - maxOffset = bb.getFromOffset(); - } - break; - case TYPE_SWITCH_DECLARATION: - for (SwitchCase switchCase : member.getSwitchCases()) { - bb = switchCase.getBasicBlock(); - if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { - end = bb; - maxOffset = bb.getFromOffset(); - } - } - break; - case TYPE_TRY_DECLARATION: - bb = member.getNext(); - if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { - end = bb; - maxOffset = bb.getFromOffset(); - } - for (ExceptionHandler exceptionHandler : member.getExceptionHandlers()) { - bb = exceptionHandler.getBasicBlock(); - if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { - end = bb; - maxOffset = bb.getFromOffset(); - } + end = searchEndBasicBlock(memberIndexes, maxOffset, members); + + if (!end.matchType(TYPE_END|TYPE_RETURN|TYPE_LOOP_START|TYPE_LOOP_CONTINUE|TYPE_LOOP_END) && + (end.getPredecessors().size() == 1) && + (end.getPredecessors().iterator().next().getLastLineNumber() + 1 >= end.getFirstLineNumber())) + { + HashSet set = new HashSet<>(); + + if (recursiveForwardSearchLastLoopMemberIndexes(members, searchZoneIndexes, set, end, null)) { + members.addAll(set); + + for (BasicBlock member : set) { + if (member.getIndex() >= 0) { + memberIndexes.set(member.getIndex()); } - break; + } + + end = searchEndBasicBlock(memberIndexes, maxOffset, set); } } } @@ -340,6 +318,55 @@ protected static Loop makeLoop(List list, BasicBlock start, BitSet s return new Loop(start, members, end); } + private static BasicBlock searchEndBasicBlock(BitSet memberIndexes, int maxOffset, Set members) { + BasicBlock end = END; + + for (BasicBlock member : members) { + switch (member.getType()) { + case TYPE_CONDITIONAL_BRANCH: + BasicBlock bb = member.getBranch(); + if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { + end = bb; + maxOffset = bb.getFromOffset(); + break; + } + case TYPE_STATEMENTS: + case TYPE_GOTO: + bb = member.getNext(); + if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { + end = bb; + maxOffset = bb.getFromOffset(); + } + break; + case TYPE_SWITCH_DECLARATION: + for (SwitchCase switchCase : member.getSwitchCases()) { + bb = switchCase.getBasicBlock(); + if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { + end = bb; + maxOffset = bb.getFromOffset(); + } + } + break; + case TYPE_TRY_DECLARATION: + bb = member.getNext(); + if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { + end = bb; + maxOffset = bb.getFromOffset(); + } + for (ExceptionHandler exceptionHandler : member.getExceptionHandlers()) { + bb = exceptionHandler.getBasicBlock(); + if (!memberIndexes.get(bb.getIndex()) && (maxOffset < bb.getFromOffset())) { + end = bb; + maxOffset = bb.getFromOffset(); + } + } + break; + } + } + + return end; + } + private static int checkMaxOffset(BasicBlock basicBlock) { int maxOffset = basicBlock.getFromOffset(); int offset; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 2a1390ee..29de4a61 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -1319,7 +1319,7 @@ protected static BasicBlock searchUpdateBlockAndCreateContinueLoop(BitSet visite int stackDepth = ByteCodeParser.evalStackDepth(subBasicBlock); while (stackDepth != 0) { - Set predecessors = basicBlock.getPredecessors(); + Set predecessors = subBasicBlock.getPredecessors(); if (predecessors.size() != 1) { break; } From 3edb5f14e2b9893253f31f13f2ef5534fdb0d1c3 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 28 Nov 2019 00:42:16 +0100 Subject: [PATCH 103/211] Fix syntax errors in decompiled sources --- .../visitor/SearchImportsVisitor.java | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java index df8d5389..245ad48c 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java @@ -23,6 +23,7 @@ public class SearchImportsVisitor extends AbstractJavaSyntaxVisitor { protected String internalPackagePrefix; protected ImportsFragment importsFragment = JavaFragmentFactory.newImportsFragment(); protected int maxLineNumber = 0; + protected HashSet mainTypeNames = new HashSet<>(); protected HashSet internalTypeNames = new HashSet<>(); public SearchImportsVisitor(String mainInternalName) { @@ -44,12 +45,27 @@ public void visit(AnnotationElementValue reference) { @Override public void visit(BodyDeclaration declaration) { + if (mainTypeNames.isEmpty()) { + mainTypeNames.add(getTypeName(declaration.getInternalTypeName())); + declaration.accept(new MainTypeVisitor(mainTypeNames)); + } if (!internalTypeNames.contains(declaration.getInternalTypeName())) { - internalTypeNames.add(declaration.getInternalTypeName()); safeAccept(declaration.getMemberDeclarations()); } } + protected static String getTypeName(String internalTypeName) { + int index = internalTypeName.lastIndexOf('$'); + if (index != -1) { + return internalTypeName.substring(index + 1); + } + index = internalTypeName.lastIndexOf('/'); + if (index != -1) { + return internalTypeName.substring(index + 1); + } + return internalTypeName; + } + public ImportsFragment getImportsFragment() { importsFragment.initLineCounts(); return importsFragment; @@ -67,8 +83,9 @@ public void visit(ObjectType type) { @Override public void visit(ArrayExpression expression) { - if (maxLineNumber < expression.getLineNumber()) + if (maxLineNumber < expression.getLineNumber()) { maxLineNumber = expression.getLineNumber(); + } expression.getExpression().accept(this); expression.getIndex().accept(this); } @@ -288,9 +305,45 @@ protected void add(ObjectType type) { if (internalName.indexOf('/', internalPackagePrefix.length()) != -1) { importsFragment.addImport(internalName, qualifiedName); } - } else { + } else if (!mainTypeNames.contains(getTypeName(internalName))) { importsFragment.addImport(internalName, qualifiedName); } } } + + protected static class MainTypeVisitor extends AbstractJavaSyntaxVisitor { + HashSet mainTypeNames; + + public MainTypeVisitor(HashSet mainTypeNames) { + this.mainTypeNames = mainTypeNames; + } + + @Override + public void visit(AnnotationDeclaration declaration) { + mainTypeNames.add(getTypeName(declaration.getInternalTypeName())); + safeAccept(declaration.getBodyDeclaration()); + } + + @Override + public void visit(ClassDeclaration declaration) { + mainTypeNames.add(getTypeName(declaration.getInternalTypeName())); + safeAccept(declaration.getBodyDeclaration()); + } + + @Override + public void visit(EnumDeclaration declaration) { + mainTypeNames.add(getTypeName(declaration.getInternalTypeName())); + safeAccept(declaration.getBodyDeclaration()); + } + + @Override + public void visit(InterfaceDeclaration declaration) { + mainTypeNames.add(getTypeName(declaration.getInternalTypeName())); + safeAccept(declaration.getBodyDeclaration()); + } + + @Override public void visit(FieldDeclaration declaration) {} + @Override public void visit(ConstructorDeclaration declaration) {} + @Override public void visit(MethodDeclaration declaration) {} + } } From 8ed4e58a5172f978ba3e1632d8f3d54dff1f6daf Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 5 Dec 2019 23:07:28 +0100 Subject: [PATCH 104/211] Fix comments --- .../converter/classfiletojavasyntax/util/TypeMaker.java | 4 ++-- .../visitor/CreateInstructionsVisitor.java | 4 ++-- .../classfiletojavasyntax/visitor/InitInnerClassVisitor.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index 96893d79..863367ab 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -238,7 +238,7 @@ private MethodTypes parseMethodSignature(String descriptor, String signature, St if (signature == null) { return parseMethodSignature(descriptor, exceptionTypeNames); } else { - // Signature does not contain synthetic parameterTypes like outer type name, for example. + // Signature does not contain synthetic parameters like outer type name, for example. MethodTypes mtDescriptor = parseMethodSignature(descriptor, exceptionTypeNames); MethodTypes mtSignature = parseMethodSignature(signature, exceptionTypeNames); @@ -298,7 +298,7 @@ private MethodTypes parseMethodSignature(String signature, String[] exceptionTyp if (methodTypes == null) { SignatureReader reader = new SignatureReader(signature); - // Type parameterTypes + // Type parameters methodTypes = new MethodTypes(); methodTypes.typeParameters = parseTypeParameters(reader); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java index 6932a3e7..65121972 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java @@ -56,7 +56,7 @@ public void visit(BodyDeclaration declaration) { if (method.getParameterTypes().isList()) { for (Type type : method.getParameterTypes()) { if (type.isObject() && (type.getName() == null)) { - // Synthetic type in parameterTypes -> synthetic method + // Synthetic type in parameters -> synthetic method method.setFlags(method.getFlags() | FLAG_SYNTHETIC); method.accept(this); break; @@ -65,7 +65,7 @@ public void visit(BodyDeclaration declaration) { } else { Type type = method.getParameterTypes().getFirst(); if (type.isObject() && (type.getName() == null)) { - // Synthetic type in parameterTypes -> synthetic method + // Synthetic type in parameters -> synthetic method method.setFlags(method.getFlags() | FLAG_SYNTHETIC); method.accept(this); break; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 407b6b72..3661ce68 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -404,7 +404,7 @@ public void visit(NewExpression expression) { BaseType parameterTypes = ne.getParameterTypes(); if (parameters != null) { - // Remove synthetic parameterTypes + // Remove synthetic parameters DefaultList syntheticInnerFieldNames = cfbd.getSyntheticInnerFieldNames(); if (parameters.isList()) { From 9b3a168487a0da81609ced0b5fba5f4cdafe0459 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 8 Dec 2019 12:06:55 +0100 Subject: [PATCH 105/211] Fix syntax errors in decompiled sources --- .../declaration/AnnotationDeclaration.java | 8 +---- .../declaration/EnumDeclaration.java | 11 ++----- .../declaration/InterfaceDeclaration.java | 10 ++----- .../declaration/ModuleDeclaration.java | 2 +- .../declaration/TypeDeclaration.java | 8 ++++- .../ClassFileAnnotationDeclaration.java | 2 +- .../declaration/ClassFileBodyDeclaration.java | 19 +++++------- .../ClassFileClassDeclaration.java | 2 +- .../declaration/ClassFileEnumDeclaration.java | 2 +- .../ClassFileInterfaceDeclaration.java | 2 +- .../declaration/ClassFileTypeDeclaration.java | 16 ++++++++++ .../processor/ConvertClassFileProcessor.java | 6 ++-- .../util/ByteCodeParser.java | 8 ++--- .../util/SwitchStatementMaker.java | 8 ++--- .../visitor/InitEnumVisitor.java | 6 ++-- .../visitor/InitInnerClassVisitor.java | 29 +++++++++++++------ .../visitor/SortMembersVisitor.java | 3 +- 17 files changed, 77 insertions(+), 65 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileTypeDeclaration.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java index 7413f52f..c8cebe38 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/AnnotationDeclaration.java @@ -11,22 +11,16 @@ public class AnnotationDeclaration extends TypeDeclaration { protected BaseFieldDeclarator annotationDeclarators; - protected BodyDeclaration bodyDeclaration; public AnnotationDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseFieldDeclarator annotationDeclarators, BodyDeclaration bodyDeclaration) { - super(annotationReferences, flags, internalName, name); + super(annotationReferences, flags, internalName, name, bodyDeclaration); this.annotationDeclarators = annotationDeclarators; - this.bodyDeclaration = bodyDeclaration; } public BaseFieldDeclarator getAnnotationDeclarators() { return annotationDeclarators; } - public BodyDeclaration getBodyDeclaration() { - return bodyDeclaration; - } - @Override public void accept(DeclarationVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java index e40775f7..abf427d6 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/EnumDeclaration.java @@ -16,19 +16,16 @@ public class EnumDeclaration extends TypeDeclaration { protected BaseType interfaces; protected List constants; - protected BodyDeclaration bodyDeclaration; public EnumDeclaration(int flags, String internalName, String name, List constants, BodyDeclaration bodyDeclaration) { - super(null, flags, internalName, name); + super(null, flags, internalName, name, bodyDeclaration); this.constants = constants; - this.bodyDeclaration = bodyDeclaration; } public EnumDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseType interfaces, List constants, BodyDeclaration bodyDeclaration) { - super(annotationReferences, flags, internalName, name); + super(annotationReferences, flags, internalName, name, bodyDeclaration); this.interfaces = interfaces; this.constants = constants; - this.bodyDeclaration = bodyDeclaration; } public BaseType getInterfaces() { @@ -39,10 +36,6 @@ public List getConstants() { return constants; } - public BodyDeclaration getBodyDeclaration() { - return bodyDeclaration; - } - @Override public void accept(DeclarationVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java index ede8720e..3080f029 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/InterfaceDeclaration.java @@ -14,18 +14,16 @@ public class InterfaceDeclaration extends TypeDeclaration { protected BaseTypeParameter typeParameters; protected BaseType interfaces; - protected BodyDeclaration bodyDeclaration; public InterfaceDeclaration(int flags, String internalName, String name, BaseType interfaces) { - super(null, flags, internalName, name); + super(null, flags, internalName, name, null); this.interfaces = interfaces; } public InterfaceDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, BaseType interfaces, BodyDeclaration bodyDeclaration) { - super(annotationReferences, flags, internalName, name); + super(annotationReferences, flags, internalName, name, bodyDeclaration); this.typeParameters = typeParameters; this.interfaces = interfaces; - this.bodyDeclaration = bodyDeclaration; } public BaseTypeParameter getTypeParameters() { @@ -36,10 +34,6 @@ public BaseType getInterfaces() { return interfaces; } - public BodyDeclaration getBodyDeclaration() { - return bodyDeclaration; - } - @Override public void accept(DeclarationVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java index bb3226d4..50617ef2 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ModuleDeclaration.java @@ -18,7 +18,7 @@ public class ModuleDeclaration extends TypeDeclaration { protected List provides; public ModuleDeclaration(int flags, String internalName, String name, String version, List requires, List exports, List opens, List uses, List provides) { - super(null, flags, internalName, name); + super(null, flags, internalName, name, null); this.version = version; this.requires = requires; this.exports = exports; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java index 6dbc674b..2554ab28 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/TypeDeclaration.java @@ -14,12 +14,14 @@ public abstract class TypeDeclaration implements BaseTypeDeclaration, MemberDecl protected int flags; protected String internalTypeName; protected String name; + protected BodyDeclaration bodyDeclaration; - protected TypeDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalTypeName, String name) { + protected TypeDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalTypeName, String name, BodyDeclaration bodyDeclaration) { this.annotationReferences = annotationReferences; this.flags = flags; this.internalTypeName = internalTypeName; this.name = name; + this.bodyDeclaration = bodyDeclaration; } public BaseAnnotationReference getAnnotationReferences() { @@ -37,4 +39,8 @@ public String getInternalTypeName() { public String getName() { return name; } + + public BodyDeclaration getBodyDeclaration() { + return bodyDeclaration; + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java index 0f0b7f5b..5ff2c3fa 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileAnnotationDeclaration.java @@ -10,7 +10,7 @@ import org.jd.core.v1.model.javasyntax.declaration.AnnotationDeclaration; import org.jd.core.v1.model.javasyntax.reference.BaseAnnotationReference; -public class ClassFileAnnotationDeclaration extends AnnotationDeclaration implements ClassFileMemberDeclaration { +public class ClassFileAnnotationDeclaration extends AnnotationDeclaration implements ClassFileTypeDeclaration { protected int firstLineNumber; public ClassFileAnnotationDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, ClassFileBodyDeclaration bodyDeclaration) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java index 022c8c29..7b9410af 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileBodyDeclaration.java @@ -9,8 +9,6 @@ import org.jd.core.v1.model.javasyntax.declaration.BaseMemberDeclaration; import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; -import org.jd.core.v1.model.javasyntax.declaration.TypeDeclaration; -import org.jd.core.v1.model.javasyntax.expression.FieldReferenceExpression; import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.TypeArgument; @@ -24,8 +22,8 @@ public class ClassFileBodyDeclaration extends BodyDeclaration implements ClassFileMemberDeclaration { protected List fieldDeclarations; protected List methodDeclarations; - protected List innerTypeDeclarations; - protected Map innerTypeMap = Collections.emptyMap(); + protected List innerTypeDeclarations; + protected Map innerTypeMap = Collections.emptyMap(); protected int firstLineNumber; protected ObjectType outerType; protected DefaultList syntheticInnerFieldNames; @@ -64,25 +62,24 @@ public void setMethodDeclarations(List } } - public List getInnerTypeDeclarations() { + public List getInnerTypeDeclarations() { return innerTypeDeclarations; } - public void setInnerTypeDeclarations(List innerTypeDeclarations) { + public void setInnerTypeDeclarations(List innerTypeDeclarations) { if (innerTypeDeclarations != null) { updateFirstLineNumber(this.innerTypeDeclarations = innerTypeDeclarations); innerTypeMap = new HashMap<>(); - for (ClassFileMemberDeclaration innerType : innerTypeDeclarations) { - TypeDeclaration td = (TypeDeclaration) innerType; - innerTypeMap.put(td.getInternalTypeName(), innerType); + for (ClassFileTypeDeclaration innerType : innerTypeDeclarations) { + innerTypeMap.put(innerType.getInternalTypeName(), innerType); } } } - public ClassFileMemberDeclaration getInnerTypeDeclaration(String internalName) { - ClassFileMemberDeclaration declaration = innerTypeMap.get(internalName); + public ClassFileTypeDeclaration getInnerTypeDeclaration(String internalName) { + ClassFileTypeDeclaration declaration = innerTypeMap.get(internalName); if ((declaration == null) && (outerBodyDeclaration != null)) { return outerBodyDeclaration.getInnerTypeDeclaration(internalName); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java index 3baff3af..c45707ae 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileClassDeclaration.java @@ -13,7 +13,7 @@ import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.ObjectType; -public class ClassFileClassDeclaration extends ClassDeclaration implements ClassFileMemberDeclaration { +public class ClassFileClassDeclaration extends ClassDeclaration implements ClassFileTypeDeclaration { protected int firstLineNumber; public ClassFileClassDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, ObjectType superType, BaseType interfaces, ClassFileBodyDeclaration bodyDeclaration) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java index d52f82ad..03d1a26e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileEnumDeclaration.java @@ -15,7 +15,7 @@ import java.util.List; -public class ClassFileEnumDeclaration extends EnumDeclaration implements ClassFileMemberDeclaration { +public class ClassFileEnumDeclaration extends EnumDeclaration implements ClassFileTypeDeclaration { protected int firstLineNumber; public ClassFileEnumDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseType interfaces, ClassFileBodyDeclaration bodyDeclaration) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java index 224dfd4b..977c3ff5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileInterfaceDeclaration.java @@ -12,7 +12,7 @@ import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; -public class ClassFileInterfaceDeclaration extends InterfaceDeclaration implements ClassFileMemberDeclaration { +public class ClassFileInterfaceDeclaration extends InterfaceDeclaration implements ClassFileTypeDeclaration { protected int firstLineNumber; public ClassFileInterfaceDeclaration(BaseAnnotationReference annotationReferences, int flags, String internalName, String name, BaseTypeParameter typeParameters, BaseType interfaces, ClassFileBodyDeclaration bodyDeclaration) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileTypeDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileTypeDeclaration.java new file mode 100644 index 00000000..17dd451a --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileTypeDeclaration.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration; + +import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; + +public interface ClassFileTypeDeclaration extends ClassFileMemberDeclaration { + String getInternalTypeName(); + int getFirstLineNumber(); + BodyDeclaration getBodyDeclaration(); +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index 61e29765..866f8b0d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -228,17 +228,17 @@ protected List convertMethods(TypeMaker } } - protected List convertInnerTypes(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { + protected List convertInnerTypes(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { List innerClassFiles = classFile.getInnerClassFiles(); if (innerClassFiles == null) { return null; } else { - DefaultList list = new DefaultList<>(innerClassFiles.size()); + DefaultList list = new DefaultList<>(innerClassFiles.size()); for (ClassFile innerClassFile : innerClassFiles) { int flags = innerClassFile.getAccessFlags(); - ClassFileMemberDeclaration innerTypeDeclaration; + ClassFileTypeDeclaration innerTypeDeclaration; if ((flags & Constants.ACC_ENUM) != 0) { innerTypeDeclaration = convertEnumDeclaration(parser, converter, innerClassFile, outerClassFileBodyDeclaration); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 2885f922..5774ff52 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -1745,12 +1745,12 @@ private Expression newNewExpression(int lineNumber, String internalTypeName) { ObjectType objectType = typeMaker.makeFromInternalTypeName(internalTypeName); if ((objectType.getQualifiedName() == null) && (objectType.getName() == null)) { - ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalTypeName); + ClassFileTypeDeclaration typeDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalTypeName); - if (memberDeclaration == null) { + if (typeDeclaration == null) { return new ClassFileNewExpression(lineNumber, ObjectType.TYPE_OBJECT); - } else if (memberDeclaration.getClass() == ClassFileClassDeclaration.class) { - ClassFileClassDeclaration declaration = (ClassFileClassDeclaration) memberDeclaration; + } else if (typeDeclaration.getClass() == ClassFileClassDeclaration.class) { + ClassFileClassDeclaration declaration = (ClassFileClassDeclaration) typeDeclaration; BodyDeclaration bodyDeclaration; if (this.internalTypeName.equals(internalTypeName)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java index ec26bd33..6b7fb963 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java @@ -11,8 +11,8 @@ import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileClassDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileTypeDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileTryStatement; @@ -187,11 +187,11 @@ public static void makeSwitchEnum(ClassFileBodyDeclaration bodyDeclaration, Swit FieldReferenceExpression fre = (FieldReferenceExpression)ae.getExpression(); if (fre.getDescriptor().equals("[I") && fre.getName().startsWith("$SwitchMap$")) { - ClassFileClassDeclaration syntheticClass = (ClassFileClassDeclaration)bodyDeclaration.getInnerTypeDeclaration(fre.getInternalTypeName()); + ClassFileTypeDeclaration syntheticClassDeclaration = bodyDeclaration.getInnerTypeDeclaration(fre.getInternalTypeName()); - if (syntheticClass != null) { + if (syntheticClassDeclaration != null) { // Javac switch-enum pattern - bodyDeclaration = (ClassFileBodyDeclaration) syntheticClass.getBodyDeclaration(); + bodyDeclaration = (ClassFileBodyDeclaration) syntheticClassDeclaration.getBodyDeclaration(); DefaultList statements = bodyDeclaration.getMethodDeclarations().get(0).getStatements().getList(); updateSwitchStatement(switchStatement, statements.listIterator(1)); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java index e6ad6f31..9d80781e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java @@ -125,9 +125,9 @@ public void visit(NewExpression expression) { String enumInternalTypeName = expression.getObjectType().getInternalName(); if (!enumInternalTypeName.equals(bodyDeclaration.getInternalTypeName())) { - ClassFileMemberDeclaration md = bodyDeclaration.getInnerTypeDeclaration(enumInternalTypeName); - if (md != null) { - constantBodyDeclaration = ((ClassFileEnumDeclaration)md).getBodyDeclaration(); + ClassFileTypeDeclaration typeDeclaration = bodyDeclaration.getInnerTypeDeclaration(enumInternalTypeName); + if (typeDeclaration != null) { + constantBodyDeclaration = typeDeclaration.getBodyDeclaration(); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 3661ce68..aefb697a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -222,13 +222,11 @@ public void visit(FieldReferenceExpression expression) { expression.setExpression(new ObjectTypeReferenceExpression(exp.getLineNumber(), outerType.createType(null))); expression.setName("this"); } else { - ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(expression.getInternalTypeName()); + ClassFileTypeDeclaration typeDeclaration = bodyDeclaration.getInnerTypeDeclaration(expression.getInternalTypeName()); - if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { - ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; - - if (cfcd.getInternalTypeName().equals(expression.getInternalTypeName())) { - ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); + if ((typeDeclaration != null) && (typeDeclaration.getClass() == ClassFileClassDeclaration.class)) { + if (typeDeclaration.getInternalTypeName().equals(expression.getInternalTypeName())) { + ClassFileBodyDeclaration cfbd = (ClassFileBodyDeclaration) typeDeclaration.getBodyDeclaration(); String outerInternalTypeName = cfbd.getOuterBodyDeclaration().getInternalTypeName(); ObjectType objectType = (ObjectType)expression.getType(); @@ -380,10 +378,23 @@ public void visit(NewExpression expression) { if (ne.getBodyDeclaration() == null) { ObjectType type = ne.getObjectType(); String internalName = type.getInternalName(); - ClassFileMemberDeclaration memberDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); + ClassFileTypeDeclaration typeDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); + + if (typeDeclaration == null) { + ClassFileBodyDeclaration bd = bodyDeclaration; - if ((memberDeclaration != null) && (memberDeclaration.getClass() == ClassFileClassDeclaration.class)) { - ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) memberDeclaration; + for (;;) { + if (bd.getInternalTypeName().equals(internalName)) { + cfbd = bd; + break; + } + bd = bd.getOuterBodyDeclaration(); + if (bd == null) { + break; + } + } + } else if (typeDeclaration.getClass() == ClassFileClassDeclaration.class) { + ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) typeDeclaration; cfbd = (ClassFileBodyDeclaration) cfcd.getBodyDeclaration(); if ((type.getQualifiedName() == null) && (type.getName() != null)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SortMembersVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SortMembersVisitor.java index 6c26bd71..0a95c19c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SortMembersVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SortMembersVisitor.java @@ -11,6 +11,7 @@ import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMemberDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileTypeDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.MergeMembersUtil; import java.util.List; @@ -25,7 +26,7 @@ public void visit(AnnotationDeclaration declaration) { @Override public void visit(BodyDeclaration declaration) { ClassFileBodyDeclaration bodyDeclaration = (ClassFileBodyDeclaration)declaration; - List innerTypes = bodyDeclaration.getInnerTypeDeclarations(); + List innerTypes = bodyDeclaration.getInnerTypeDeclarations(); // Merge fields, getters & inner types BaseMemberDeclaration members = MergeMembersUtil.merge(bodyDeclaration.getFieldDeclarations(), bodyDeclaration.getMethodDeclarations(), innerTypes); bodyDeclaration.setMemberDeclarations(members); From db03b6b6e98d5bfa0aa6f35631f48493d0ebd670 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 9 Dec 2019 09:58:10 +0100 Subject: [PATCH 106/211] Fix syntax errors in decompiled sources --- .../visitor/InitInnerClassVisitor.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index aefb697a..9e482413 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -381,17 +381,11 @@ public void visit(NewExpression expression) { ClassFileTypeDeclaration typeDeclaration = bodyDeclaration.getInnerTypeDeclaration(internalName); if (typeDeclaration == null) { - ClassFileBodyDeclaration bd = bodyDeclaration; - - for (;;) { + for (ClassFileBodyDeclaration bd = bodyDeclaration; bd != null; bd = bd.getOuterBodyDeclaration()) { if (bd.getInternalTypeName().equals(internalName)) { cfbd = bd; break; } - bd = bd.getOuterBodyDeclaration(); - if (bd == null) { - break; - } } } else if (typeDeclaration.getClass() == ClassFileClassDeclaration.class) { ClassFileClassDeclaration cfcd = (ClassFileClassDeclaration) typeDeclaration; From 1a79b9e49b0dc015ca73787530ff6b5501e34577 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 9 Dec 2019 10:16:11 +0100 Subject: [PATCH 107/211] Fix syntax errors in decompiled sources --- .../visitor/PopulateBindingsWithTypeArgumentVisitor.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java index 9e97e35b..39e574e4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java @@ -90,12 +90,8 @@ public void visit(TypeArguments arguments) { } } - protected boolean equals(BaseType bt1, BaseType bt2) { - if (bt1 == null) { - return (bt2 == null); - } else { - return (bt2 != null) && bt1.equals(bt2); - } + private static boolean equals(BaseType bt1, BaseType bt2) { + return (bt2 == null) || bt2.equals(bt1); } protected TypeArgument checkTypeClassCheckDimensionAndReturnCurrentAsTypeArgument(GenericType type) { From b6b7551f65d5106cf25ba8dca1f735b2ec61d060 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 9 Dec 2019 11:09:54 +0100 Subject: [PATCH 108/211] Fix syntax errors in decompiled sources --- .../classfiletojavasyntax/util/LocalVariableMaker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 38cfdc34..bf14838e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -339,7 +339,7 @@ public boolean isCompatible(AbstractLocalVariable lv, Type valueType) { BaseTypeArgument lvTypeArguments = lvObjectType.getTypeArguments(); BaseTypeArgument valueTypeArguments = valueObjectType.getTypeArguments(); - if ((lvTypeArguments == null) || (valueTypeArguments == null)) { + if ((lvTypeArguments == null) || (valueTypeArguments == null) || (valueTypeArguments == WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT)) { return typeMaker.isRawTypeAssignable(lvObjectType, valueObjectType); } From b8d7a06f47bd8b4a0b7bfe3279327dc19af0220b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 9 Dec 2019 18:19:04 +0100 Subject: [PATCH 109/211] Fix syntax errors in decompiled sources --- .../visitor/AddCastExpressionVisitor.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index fcee997d..295badab 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -21,6 +21,8 @@ import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; public class AddCastExpressionVisitor extends AbstractJavaSyntaxVisitor { + protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); + protected TypeMaker typeMaker; protected Type returnedType; protected Type type; @@ -177,7 +179,7 @@ public void visit(MethodInvocationExpression expression) { parameters.accept(this); expression.setParameters(updateExpressions(mie.getParameterTypes(), parameters)); } - + expression.getExpression().accept(this); } @@ -203,6 +205,19 @@ public void visit(NewInitializedArray expression) { } } + @Override + public void visit(FieldReferenceExpression expression) { + Expression exp = expression.getExpression(); + + if ((exp != null) && (exp.getClass() != ObjectTypeReferenceExpression.class)) { + Type type = typeMaker.makeFromInternalTypeName(expression.getInternalTypeName()); + + if (type.getName() != null) { + expression.setExpression(updateExpression(type, exp)); + } + } + } + @Override public void visit(BinaryOperatorExpression expression) { expression.getLeftExpression().accept(this); @@ -313,7 +328,7 @@ private static final boolean match(Expression expression) { return true; } - private static final Expression addCastExpression(Type type, Expression expression) { + private Expression addCastExpression(Type type, Expression expression) { if (expression.getClass() == CastExpression.class) { CastExpression ce = (CastExpression)expression; @@ -324,7 +339,9 @@ private static final Expression addCastExpression(Type type, Expression expressi return ce; } } else { - return new CastExpression(expression.getLineNumber(), type, expression); + searchFirstLineNumberVisitor.init(); + expression.accept(searchFirstLineNumberVisitor); + return new CastExpression(searchFirstLineNumberVisitor.getLineNumber(), type, expression); } } From e2163321a56856ed0b89762275561257cfd4e4f1 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 16 Dec 2019 17:57:13 +0100 Subject: [PATCH 110/211] Fix syntax errors in decompiled sources --- .../javasyntax/type/BaseTypeArgument.java | 4 +- .../javasyntax/type/DiamondTypeArgument.java | 4 +- .../v1/model/javasyntax/type/GenericType.java | 4 +- .../v1/model/javasyntax/type/ObjectType.java | 51 ++++++++++-- .../model/javasyntax/type/PrimitiveType.java | 4 +- .../model/javasyntax/type/TypeArguments.java | 5 +- .../type/WildcardExtendsTypeArgument.java | 8 +- .../type/WildcardSuperTypeArgument.java | 8 +- .../javasyntax/type/WildcardTypeArgument.java | 4 +- .../ClassFileConstructorDeclaration.java | 24 +++++- ...assFileConstructorOrMethodDeclaration.java | 7 ++ .../ClassFileMethodDeclaration.java | 34 ++++++-- ...ClassFileStaticInitializerDeclaration.java | 21 ++++- .../localvariable/AbstractLocalVariable.java | 20 ++--- .../model/localvariable/Frame.java | 16 ++-- .../localvariable/GenericLocalVariable.java | 15 ++-- .../localvariable/ObjectLocalVariable.java | 49 +++++++----- .../localvariable/PrimitiveLocalVariable.java | 23 +++--- .../processor/ConvertClassFileProcessor.java | 72 ++++++++++------- .../util/ByteCodeParser.java | 78 +++++++++---------- .../util/LocalVariableMaker.java | 27 ++++--- .../util/LoopStatementMaker.java | 32 +++++--- .../util/StatementMaker.java | 19 +++-- .../classfiletojavasyntax/util/TypeMaker.java | 5 +- .../TypeParametersToTypeArgumentsBinder.java | 37 ++------- .../visitor/AddCastExpressionVisitor.java | 53 ++++++++++++- ...pulateBindingsWithTypeArgumentVisitor.java | 4 +- .../org/jd/core/v1/MergeMembersUtilTest.java | 29 ++++--- .../java/org/jd/core/v1/TypeMakerTest.java | 49 ++++++------ 29 files changed, 449 insertions(+), 257 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java index 0d15edcc..1ee29450 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/BaseTypeArgument.java @@ -9,9 +9,11 @@ import org.jd.core.v1.util.DefaultList; +import java.util.Map; + @SuppressWarnings("unchecked") public interface BaseTypeArgument extends TypeArgumentVisitable { - default boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + default boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { return false; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java index 3c5679cd..23868210 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/DiamondTypeArgument.java @@ -7,6 +7,8 @@ package org.jd.core.v1.model.javasyntax.type; +import java.util.Map; + public class DiamondTypeArgument implements TypeArgument { public static final DiamondTypeArgument DIAMOND = new DiamondTypeArgument(); @@ -18,7 +20,7 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { return true; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java index 1f6a7c48..acd89387 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/GenericType.java @@ -7,6 +7,8 @@ package org.jd.core.v1.model.javasyntax.type; +import java.util.Map; + public class GenericType implements Type { protected String name; protected int dimension; @@ -76,7 +78,7 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { Class typeArgumentClass = typeArgument.getClass(); if (typeArgumentClass == GenericType.class) { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java index b9ec7d46..91501d6e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/ObjectType.java @@ -7,6 +7,8 @@ package org.jd.core.v1.model.javasyntax.type; +import java.util.Map; + public class ObjectType implements Type { public static final ObjectType TYPE_BOOLEAN = new ObjectType("java/lang/Boolean", "java.lang.Boolean", "Boolean"); public static final ObjectType TYPE_BYTE = new ObjectType("java/lang/Byte", "java.lang.Byte", "Byte"); @@ -203,25 +205,60 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { Class typeArgumentClass = typeArgument.getClass(); - if ((typeArgumentClass != ObjectType.class) && (typeArgumentClass != InnerObjectType.class)) { - return false; + if ((typeArgumentClass == ObjectType.class) || (typeArgumentClass == InnerObjectType.class)) { + ObjectType ot = (ObjectType)typeArgument; + + if ((dimension != ot.getDimension()) || !internalName.equals(ot.getInternalName())) { + return false; + } + + if (ot.getTypeArguments() == null) { + return (typeArguments == null); + } else if (typeArguments == null) { + return false; + } else { + return typeArguments.isTypeArgumentAssignableFrom(typeBounds, ot.getTypeArguments()); + } } - ObjectType ot = (ObjectType)typeArgument; + if (typeArgumentClass == GenericType.class) { + GenericType gt = (GenericType)typeArgument; + BaseType bt = typeBounds.get(gt.getName()); + + if (bt != null) { + for (Type type : bt) { + if (dimension == type.getDimension()) { + Class typeClass = type.getClass(); + + if ((typeClass == ObjectType.class) || (typeClass == InnerObjectType.class)) { + ObjectType ot = (ObjectType) type; + + if (internalName.equals(ot.getInternalName())) { + return true; + } + } + } + } + } + } + + return false; + } - if ((dimension != ot.getDimension()) || !internalName.equals(ot.getInternalName())) { + protected boolean isTypeArgumentAssignableFrom(Map typeBounds, ObjectType objectType) { + if ((dimension != objectType.getDimension()) || !internalName.equals(objectType.getInternalName())) { return false; } - if (ot.getTypeArguments() == null) { + if (objectType.getTypeArguments() == null) { return (typeArguments == null); } else if (typeArguments == null) { return false; } else { - return typeArguments.isTypeArgumentAssignableFrom(ot.getTypeArguments()); + return typeArguments.isTypeArgumentAssignableFrom(typeBounds, objectType.getTypeArguments()); } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java index 4eedc364..170410c3 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/PrimitiveType.java @@ -7,6 +7,8 @@ package org.jd.core.v1.model.javasyntax.type; +import java.util.Map; + public class PrimitiveType implements Type { public static final int FLAG_BOOLEAN = 1; public static final int FLAG_CHAR = 2; @@ -159,7 +161,7 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { return equals(typeArgument); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArguments.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArguments.java index f7853362..eabe9755 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArguments.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeArguments.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.Iterator; +import java.util.Map; public class TypeArguments extends DefaultList implements BaseTypeArgument { public TypeArguments() {} @@ -29,7 +30,7 @@ public boolean isList() { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { if (typeArgument.getClass() != TypeArguments.class) { return false; } @@ -44,7 +45,7 @@ public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { Iterator iterator2 = ata.iterator(); while (iterator1.hasNext()) { - if (!iterator1.next().isTypeArgumentAssignableFrom(iterator2.next())) { + if (!iterator1.next().isTypeArgumentAssignableFrom(typeBounds, iterator2.next())) { return false; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java index 2ddfb058..3e917ebb 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardExtendsTypeArgument.java @@ -7,6 +7,8 @@ package org.jd.core.v1.model.javasyntax.type; +import java.util.Map; + public class WildcardExtendsTypeArgument implements TypeArgument { protected Type type; @@ -24,11 +26,11 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { if (typeArgument.getClass() == WildcardExtendsTypeArgument.class) { - return type.isTypeArgumentAssignableFrom(((WildcardExtendsTypeArgument)typeArgument).getType()); + return type.isTypeArgumentAssignableFrom(typeBounds, ((WildcardExtendsTypeArgument)typeArgument).getType()); } else if (typeArgument instanceof Type) { - return type.isTypeArgumentAssignableFrom(typeArgument); + return type.isTypeArgumentAssignableFrom(typeBounds, typeArgument); } return false; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java index 5d0f6b13..ebf1af40 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardSuperTypeArgument.java @@ -7,6 +7,8 @@ package org.jd.core.v1.model.javasyntax.type; +import java.util.Map; + public class WildcardSuperTypeArgument implements TypeArgument { protected Type type; @@ -24,11 +26,11 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { if (typeArgument.getClass() == WildcardSuperTypeArgument.class) { - return type.isTypeArgumentAssignableFrom(((WildcardSuperTypeArgument)typeArgument).getType()); + return type.isTypeArgumentAssignableFrom(typeBounds, ((WildcardSuperTypeArgument)typeArgument).getType()); } else if (typeArgument instanceof Type) { - return type.isTypeArgumentAssignableFrom(typeArgument); + return type.isTypeArgumentAssignableFrom(typeBounds, typeArgument); } return false; diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java index fa586fcd..77416317 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/WildcardTypeArgument.java @@ -7,6 +7,8 @@ package org.jd.core.v1.model.javasyntax.type; +import java.util.Map; + public class WildcardTypeArgument implements TypeArgument { public static final WildcardTypeArgument WILDCARD_TYPE_ARGUMENT = new WildcardTypeArgument(); @@ -18,7 +20,7 @@ public void accept(TypeArgumentVisitor visitor) { } @Override - public boolean isTypeArgumentAssignableFrom(BaseTypeArgument typeArgument) { + public boolean isTypeArgumentAssignableFrom(Map typeBounds, BaseTypeArgument typeArgument) { return true; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java index 93cbc5b6..c3e5a423 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java @@ -16,23 +16,31 @@ import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.TypeArgument; + +import java.util.Map; public class ClassFileConstructorDeclaration extends ConstructorDeclaration implements ClassFileConstructorOrMethodDeclaration { protected ClassFileBodyDeclaration bodyDeclaration; protected ClassFile classFile; protected Method method; protected BaseType parameterTypes; + protected Map bindings; + protected Map typeBounds; protected int firstLineNumber; public ClassFileConstructorDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, BaseAnnotationReference annotationReferences, - BaseTypeParameter typeParameters, BaseType parameterTypes, BaseType exceptions, int firstLineNumber) { + BaseTypeParameter typeParameters, BaseType parameterTypes, BaseType exceptions, Map bindings, + Map typeBounds, int firstLineNumber) { super(annotationReferences, method.getAccessFlags(), typeParameters, null, exceptions, method.getDescriptor(), null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; - this.firstLineNumber = firstLineNumber; - this.parameterTypes = parameterTypes; this.method = method; + this.parameterTypes = parameterTypes; + this.bindings = bindings; + this.typeBounds = typeBounds; + this.firstLineNumber = firstLineNumber; } @Override @@ -75,6 +83,16 @@ public Type getReturnedType() { return null; } + @Override + public Map getBindings() { + return bindings; + } + + @Override + public Map getTypeBounds() { + return typeBounds; + } + @Override public int getFirstLineNumber() { return firstLineNumber; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java index 16184dd6..6f716bca 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorOrMethodDeclaration.java @@ -14,6 +14,9 @@ import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.TypeArgument; + +import java.util.Map; public interface ClassFileConstructorOrMethodDeclaration extends ClassFileMemberDeclaration { int getFlags(); @@ -31,6 +34,10 @@ public interface ClassFileConstructorOrMethodDeclaration extends ClassFileMember ClassFileBodyDeclaration getBodyDeclaration(); + Map getBindings(); + + Map getTypeBounds(); + void setFormalParameters(BaseFormalParameter formalParameters); BaseStatement getStatements(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java index cc5ed19c..217fff70 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java @@ -17,44 +17,58 @@ import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.TypeArgument; + +import java.util.Map; public class ClassFileMethodDeclaration extends MethodDeclaration implements ClassFileConstructorOrMethodDeclaration { protected ClassFileBodyDeclaration bodyDeclaration; protected ClassFile classFile; protected Method method; protected BaseType parameterTypes; + protected Map bindings; + protected Map typeBounds; protected int firstLineNumber; public ClassFileMethodDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, String name, - Type returnedType, BaseType parameterTypes) { + Type returnedType, BaseType parameterTypes, Map bindings, + Map typeBounds) { super(null, method.getAccessFlags(), name, null, returnedType, null, null, method.getDescriptor(), null, null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; this.parameterTypes = parameterTypes; this.method = method; + this.bindings = bindings; + this.typeBounds = typeBounds; } public ClassFileMethodDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, String name, - Type returnedType, BaseType parameterTypes, int firstLineNumber) { + Type returnedType, BaseType parameterTypes, Map bindings, + Map typeBounds, int firstLineNumber) { super(null, method.getAccessFlags(), name, null, returnedType, null, null, method.getDescriptor(), null, null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; - this.parameterTypes = parameterTypes; this.method = method; + this.parameterTypes = parameterTypes; + this.bindings = bindings; + this.typeBounds = typeBounds; this.firstLineNumber = firstLineNumber; } public ClassFileMethodDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, BaseAnnotationReference annotationReferences, String name, BaseTypeParameter typeParameters, Type returnedType, BaseType parameterTypes, BaseType exceptions, - ElementValue defaultAnnotationValue, int firstLineNumber) { + ElementValue defaultAnnotationValue, Map bindings, + Map typeBounds, int firstLineNumber) { super(annotationReferences, method.getAccessFlags(), name, typeParameters, returnedType, null, exceptions, method.getDescriptor(), null, defaultAnnotationValue); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; - this.parameterTypes = parameterTypes; this.method = method; + this.parameterTypes = parameterTypes; + this.bindings = bindings; + this.typeBounds = typeBounds; this.firstLineNumber = firstLineNumber; } @@ -93,6 +107,16 @@ public BaseType getParameterTypes() { return parameterTypes; } + @Override + public Map getBindings() { + return bindings; + } + + @Override + public Map getTypeBounds() { + return typeBounds; + } + @Override public int getFirstLineNumber() { return firstLineNumber; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java index e5be2da5..c9213abf 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileStaticInitializerDeclaration.java @@ -15,18 +15,27 @@ import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.BaseTypeParameter; import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.TypeArgument; + +import java.util.Map; public class ClassFileStaticInitializerDeclaration extends StaticInitializerDeclaration implements ClassFileConstructorOrMethodDeclaration { protected ClassFileBodyDeclaration bodyDeclaration; protected ClassFile classFile; protected Method method; + protected Map bindings; + protected Map typeBounds; protected int firstLineNumber = 0; - public ClassFileStaticInitializerDeclaration(ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, int firstLineNumber) { + public ClassFileStaticInitializerDeclaration( + ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, Map bindings, + Map typeBounds, int firstLineNumber) { super(method.getDescriptor(), null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; this.method = method; + this.bindings = bindings; + this.typeBounds = typeBounds; this.firstLineNumber = firstLineNumber; } @@ -72,6 +81,16 @@ public ClassFileBodyDeclaration getBodyDeclaration() { return bodyDeclaration; } + @Override + public Map getBindings() { + return bindings; + } + + @Override + public Map getTypeBounds() { + return typeBounds; + } + @Override public int getFirstLineNumber() { return firstLineNumber; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java index c29a56d7..e3faed3a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java @@ -7,10 +7,12 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.util.DefaultList; import java.util.HashSet; +import java.util.Map; public abstract class AbstractLocalVariable { protected Frame frame; @@ -79,23 +81,23 @@ public void setToOffset(int offset) { * Determines if the local variable represented by this object is either the same as, or is a super type variable * of, the local variable represented by the specified parameter. */ - public abstract boolean isAssignableFrom(Type type); - public abstract void typeOnRight(Type type); - public abstract void typeOnLeft(Type type); + public abstract boolean isAssignableFrom(Map typeBounds, Type type); + public abstract void typeOnRight(Map typeBounds, Type type); + public abstract void typeOnLeft(Map typeBounds, Type type); - public abstract boolean isAssignableFrom(AbstractLocalVariable variable); - public abstract void variableOnRight(AbstractLocalVariable variable); - public abstract void variableOnLeft(AbstractLocalVariable variable); + public abstract boolean isAssignableFrom(Map typeBounds, AbstractLocalVariable variable); + public abstract void variableOnRight(Map typeBounds, AbstractLocalVariable variable); + public abstract void variableOnLeft(Map typeBounds, AbstractLocalVariable variable); - protected void fireChangeEvent() { + protected void fireChangeEvent(Map typeBounds) { if (variablesOnLeft != null) { for (AbstractLocalVariable v : variablesOnLeft) { - v.variableOnRight(this); + v.variableOnRight(typeBounds, this); } } if (variablesOnRight != null) { for (AbstractLocalVariable v : variablesOnRight) { - v.variableOnLeft(this); + v.variableOnLeft(typeBounds, this); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index d2079502..adda345a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -83,7 +83,7 @@ public void setExceptionLocalVariable(AbstractLocalVariable exceptionLocalVariab this.exceptionLocalVariable = exceptionLocalVariable; } - public void mergeLocalVariable(LocalVariableMaker localVariableMaker, AbstractLocalVariable lv) { + public void mergeLocalVariable(Map typeBounds, LocalVariableMaker localVariableMaker, AbstractLocalVariable lv) { int index = lv.getIndex(); AbstractLocalVariable alvToMerge; @@ -94,7 +94,7 @@ public void mergeLocalVariable(LocalVariableMaker localVariableMaker, AbstractLo } if (alvToMerge != null) { - if (!lv.isAssignableFrom(alvToMerge) && !alvToMerge.isAssignableFrom(lv)) { + if (!lv.isAssignableFrom(typeBounds, alvToMerge) && !alvToMerge.isAssignableFrom(typeBounds, lv)) { alvToMerge = null; } else if ((lv.getName() != null) && (alvToMerge.getName() != null) && !lv.getName().equals(alvToMerge.getName())) { alvToMerge = null; @@ -104,7 +104,7 @@ public void mergeLocalVariable(LocalVariableMaker localVariableMaker, AbstractLo if (alvToMerge == null) { if (children != null) { for (Frame frame : children) { - frame.mergeLocalVariable(localVariableMaker, lv); + frame.mergeLocalVariable(typeBounds, localVariableMaker, lv); } } } else if (lv != alvToMerge) { @@ -115,24 +115,24 @@ public void mergeLocalVariable(LocalVariableMaker localVariableMaker, AbstractLo lv.getReferences().addAll(alvToMerge.getReferences()); lv.setFromOffset(alvToMerge.getFromOffset()); - if (!lv.isAssignableFrom(alvToMerge) && !localVariableMaker.isCompatible(lv, alvToMerge.getType())) { + if (!lv.isAssignableFrom(typeBounds, alvToMerge) && !localVariableMaker.isCompatible(lv, alvToMerge.getType())) { Type type = lv.getType(); Type alvToMergeType = alvToMerge.getType(); assert (type.isPrimitive() == alvToMergeType.isPrimitive()) && (type.isObject() == alvToMergeType.isObject()) && (type.isGeneric() == alvToMergeType.isGeneric()) : "Frame.mergeLocalVariable(lv) : merge local variable failed"; if (type.isPrimitive()) { - if (alvToMerge.isAssignableFrom(lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { + if (alvToMerge.isAssignableFrom(typeBounds, lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { ((PrimitiveLocalVariable)lv).setType((PrimitiveType)alvToMergeType); } else { ((PrimitiveLocalVariable)lv).setType(PrimitiveType.TYPE_INT); } } else if (type.isObject()) { - if (alvToMerge.isAssignableFrom(lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { - ((ObjectLocalVariable)lv).setType(alvToMergeType); + if (alvToMerge.isAssignableFrom(typeBounds, lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { + ((ObjectLocalVariable)lv).setType(typeBounds, alvToMergeType); } else { int dimension = Math.max(lv.getDimension(), alvToMerge.getDimension()); - ((ObjectLocalVariable)lv).setType(ObjectType.TYPE_OBJECT.createType(dimension)); + ((ObjectLocalVariable)lv).setType(typeBounds, ObjectType.TYPE_OBJECT.createType(dimension)); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java index b97fff7b..602f6729 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/GenericLocalVariable.java @@ -7,9 +7,12 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.GenericType; import org.jd.core.v1.model.javasyntax.type.Type; +import java.util.Map; + public class GenericLocalVariable extends AbstractLocalVariable { protected GenericType type; @@ -62,13 +65,13 @@ public String toString() { return sb.append("}").toString(); } - @Override public boolean isAssignableFrom(Type otherType) { + @Override public boolean isAssignableFrom(Map typeBounds, Type otherType) { return type.equals(otherType); } - @Override public void typeOnRight(Type type) {} - @Override public void typeOnLeft(Type type) {} + @Override public void typeOnRight(Map typeBounds, Type type) {} + @Override public void typeOnLeft(Map typeBounds, Type type) {} - @Override public boolean isAssignableFrom(AbstractLocalVariable variable) { return isAssignableFrom(variable.getType()); } - @Override public void variableOnRight(AbstractLocalVariable variable) {} - @Override public void variableOnLeft(AbstractLocalVariable variable) {} + @Override public boolean isAssignableFrom(Map typeBounds, AbstractLocalVariable variable) { return isAssignableFrom(typeBounds, variable.getType()); } + @Override public void variableOnRight(Map typeBounds, AbstractLocalVariable variable) {} + @Override public void variableOnLeft(Map typeBounds, AbstractLocalVariable variable) {} } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 2dabbff0..d9177ac4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -7,10 +7,13 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; +import java.util.Map; + import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; @@ -40,10 +43,10 @@ public Type getType() { return type; } - public void setType(Type type) { + public void setType(Map typeBounds, Type type) { if (!this.type.equals(type)) { this.type = type; - fireChangeEvent(); + fireChangeEvent(typeBounds); } } @@ -78,7 +81,7 @@ public String toString() { } @Override - public boolean isAssignableFrom(Type type) { + public boolean isAssignableFrom(Map typeBounds, Type type) { if (this.type.isObject()) { if (this.type.equals(TYPE_OBJECT)) { if ((type.getDimension() > 0) || !type.isPrimitive()) { @@ -87,18 +90,19 @@ public boolean isAssignableFrom(Type type) { } if (type.isObject()) { - return typeMaker.isAssignable((ObjectType) this.type, (ObjectType) type); + return typeMaker.isAssignable(typeBounds, (ObjectType) this.type, (ObjectType) type); } } return false; } - public void typeOnRight(Type type) { + @Override + public void typeOnRight(Map typeBounds, Type type) { if (type != TYPE_UNDEFINED_OBJECT) { if (this.type == TYPE_UNDEFINED_OBJECT) { this.type = type; - fireChangeEvent(); + fireChangeEvent(typeBounds); } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { assert !this.type.isPrimitive() && !type.isPrimitive() : "ObjectLocalVariable.typeOnRight(type) : unexpected type"; @@ -112,32 +116,33 @@ public void typeOnRight(Type type) { if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { // Keep type, update type arguments this.type = otherObjectType; - fireChangeEvent(); + fireChangeEvent(typeBounds); } - } else if (typeMaker.isAssignable(thisObjectType, otherObjectType)) { + } else if (typeMaker.isAssignable(typeBounds, thisObjectType, otherObjectType)) { // Assignable types if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { // Keep type, update type arguments this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); - fireChangeEvent(); + fireChangeEvent(typeBounds); } } } } else if (this.type.isGeneric()) { if (type.isGeneric()) { this.type = type; - fireChangeEvent(); + fireChangeEvent(typeBounds); } } } } } - public void typeOnLeft(Type type) { + @Override + public void typeOnLeft(Map typeBounds, Type type) { if (type != TYPE_UNDEFINED_OBJECT) { if (this.type == TYPE_UNDEFINED_OBJECT) { this.type = type; - fireChangeEvent(); + fireChangeEvent(typeBounds); } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { assert !this.type.isPrimitive() && !type.isPrimitive() : "unexpected type in ObjectLocalVariable.typeOnLeft(type)"; @@ -151,14 +156,14 @@ public void typeOnLeft(Type type) { if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { // Keep type, update type arguments this.type = otherObjectType; - fireChangeEvent(); + fireChangeEvent(typeBounds); } - } else if (typeMaker.isAssignable(otherObjectType, thisObjectType)) { + } else if (typeMaker.isAssignable(typeBounds, otherObjectType, thisObjectType)) { // Assignable types if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { // Keep type, update type arguments this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); - fireChangeEvent(); + fireChangeEvent(typeBounds); } } } @@ -168,17 +173,19 @@ public void typeOnLeft(Type type) { } @Override - public boolean isAssignableFrom(AbstractLocalVariable variable) { - return isAssignableFrom(variable.getType()); + public boolean isAssignableFrom(Map typeBounds, AbstractLocalVariable variable) { + return isAssignableFrom(typeBounds, variable.getType()); } - public void variableOnRight(AbstractLocalVariable variable) { + @Override + public void variableOnRight(Map typeBounds, AbstractLocalVariable variable) { addVariableOnRight(variable); - typeOnRight(variable.getType()); + typeOnRight(typeBounds, variable.getType()); } - public void variableOnLeft(AbstractLocalVariable variable) { + @Override + public void variableOnLeft(Map typeBounds, AbstractLocalVariable variable) { addVariableOnLeft(variable); - typeOnLeft(variable.getType()); + typeOnLeft(typeBounds, variable.getType()); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java index 5790556e..99d92477 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/PrimitiveLocalVariable.java @@ -7,10 +7,13 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; +import java.util.Map; + import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; public class PrimitiveLocalVariable extends AbstractLocalVariable { @@ -119,7 +122,7 @@ public String toString() { } @Override - public boolean isAssignableFrom(Type type) { + public boolean isAssignableFrom(Map typeBounds, Type type) { if ((type.getDimension() == 0) && type.isPrimitive()) { return (flags & ((PrimitiveType)type).getRightFlags()) != 0; } @@ -128,7 +131,7 @@ public boolean isAssignableFrom(Type type) { } @Override - public void typeOnRight(Type type) { + public void typeOnRight(Map typeBounds, Type type) { if (type.isPrimitive()) { assert (type.getDimension() == 0); @@ -140,14 +143,14 @@ public void typeOnRight(Type type) { flags &= f; if (old != flags) { - fireChangeEvent(); + fireChangeEvent(typeBounds); } } } } @Override - public void typeOnLeft(Type type) { + public void typeOnLeft(Map typeBounds, Type type) { if (type.isPrimitive()) { assert (type.getDimension() == 0); @@ -159,14 +162,14 @@ public void typeOnLeft(Type type) { flags &= f; if (old != flags) { - fireChangeEvent(); + fireChangeEvent(typeBounds); } } } } @Override - public boolean isAssignableFrom(AbstractLocalVariable variable) { + public boolean isAssignableFrom(Map typeBounds, AbstractLocalVariable variable) { if (variable.getClass() == PrimitiveLocalVariable.class) { int variableFlags = ((PrimitiveLocalVariable)variable).flags; PrimitiveType type = PrimitiveTypeUtil.getPrimitiveTypeFromFlags(variableFlags); @@ -182,7 +185,7 @@ public boolean isAssignableFrom(AbstractLocalVariable variable) { } @Override - public void variableOnRight(AbstractLocalVariable variable) { + public void variableOnRight(Map typeBounds, AbstractLocalVariable variable) { assert variable.getDimension() == 0; addVariableOnRight(variable); @@ -199,12 +202,12 @@ public void variableOnRight(AbstractLocalVariable variable) { assert flags != 0 : "PrimitiveLocalVariable.variableOnRight(var) : flags = 0 after type reduction"; if (old != flags) { - fireChangeEvent(); + fireChangeEvent(typeBounds); } } @Override - public void variableOnLeft(AbstractLocalVariable variable) { + public void variableOnLeft(Map typeBounds, AbstractLocalVariable variable) { assert variable.getDimension() == 0; addVariableOnLeft(variable); @@ -221,7 +224,7 @@ public void variableOnLeft(AbstractLocalVariable variable) { assert flags != 0 : "PrimitiveLocalVariable.variableOnLeft(var) : flags = 0 after type reduction"; if (old != flags) { - fireChangeEvent(); + fireChangeEvent(typeBounds); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index 866f8b0d..ac6ca2c1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -41,7 +41,17 @@ * Output: {@link org.jd.core.v1.model.javasyntax.CompilationUnit}
*/ public class ConvertClassFileProcessor implements Processor { - protected PopulateBindingsWithTypeParameterVisitor populateBindingsWithTypeParameterVisitor = new PopulateBindingsWithTypeParameterVisitor(); + protected PopulateBindingsWithTypeParameterVisitor populateBindingsWithTypeParameterVisitor = new PopulateBindingsWithTypeParameterVisitor() { + @Override + public void visit(TypeParameter type) { + bindings.put(type.getIdentifier(), new GenericType(type.getIdentifier())); + } + @Override + public void visit(TypeParameterWithTypeBounds type) { + bindings.put(type.getIdentifier(), new GenericType(type.getIdentifier())); + typeBounds.put(type.getIdentifier(), type.getTypeBounds()); + } + }; @Override public void process(Message message) throws Exception { @@ -116,31 +126,20 @@ protected ClassFileClassDeclaration convertClassDeclaration(TypeMaker parser, An } protected ClassFileBodyDeclaration convertBodyDeclaration(TypeMaker parser, AnnotationConverter converter, ClassFile classFile, BaseTypeParameter typeParameters, ClassFileBodyDeclaration outerClassFileBodyDeclaration) { - Map bindings = Collections.emptyMap(); - Map typeBounds = Collections.emptyMap(); + Map bindings; + Map typeBounds; - if (typeParameters == null) { - if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null)) { - bindings = outerClassFileBodyDeclaration.getBindings(); - typeBounds = outerClassFileBodyDeclaration.getTypeBounds(); - } + if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null)) { + bindings = outerClassFileBodyDeclaration.getBindings(); + typeBounds = outerClassFileBodyDeclaration.getTypeBounds(); } else { - bindings = new HashMap<>(); - typeBounds = new HashMap<>(); + bindings = Collections.emptyMap(); + typeBounds = Collections.emptyMap(); + } - populateBindingsWithTypeParameterVisitor.init(bindings, typeBounds); + if (typeParameters != null) { + populateBindingsWithTypeParameterVisitor.init(bindings=new HashMap<>(bindings), typeBounds=new HashMap<>(typeBounds)); typeParameters.accept(populateBindingsWithTypeParameterVisitor); - - for (Map.Entry entry : bindings.entrySet()) { - if (entry.getValue() == null) { - entry.setValue(new GenericType(entry.getKey())); - } - } - - if (((classFile.getAccessFlags() & ACC_STATIC) == 0) && (outerClassFileBodyDeclaration != null)) { - bindings.putAll(outerClassFileBodyDeclaration.getBindings()); - typeBounds.putAll(outerClassFileBodyDeclaration.getTypeBounds()); - } } ClassFileBodyDeclaration bodyDeclaration = new ClassFileBodyDeclaration(classFile.getInternalTypeName(), bindings, typeBounds, outerClassFileBodyDeclaration); @@ -191,6 +190,23 @@ protected List convertMethods(TypeMaker defaultAnnotationValue = converter.convert(annotationDefault.getDefaultValue()); } + TypeMaker.MethodTypes methodTypes = parser.parseMethodSignature(classFile, method); + Map bindings; + Map typeBounds; + + if ((method.getAccessFlags() & ACC_STATIC) == 0) { + bindings = bodyDeclaration.getBindings(); + typeBounds = bodyDeclaration.getTypeBounds(); + } else { + bindings = Collections.emptyMap(); + typeBounds = Collections.emptyMap(); + } + + if (methodTypes.typeParameters != null) { + populateBindingsWithTypeParameterVisitor.init(bindings=new HashMap<>(bindings), typeBounds=new HashMap<>(typeBounds)); + methodTypes.typeParameters.accept(populateBindingsWithTypeParameterVisitor); + } + AttributeCode code = method.getAttribute("Code"); int firstLineNumber = 0; @@ -202,25 +218,23 @@ protected List convertMethods(TypeMaker } if ("".equals(name)) { - TypeMaker.MethodTypes methodTypes = parser.parseMethodSignature(classFile, method); list.add(new ClassFileConstructorDeclaration( bodyDeclaration, classFile, method, annotationReferences, methodTypes.typeParameters, - methodTypes.parameterTypes, methodTypes.exceptions, firstLineNumber)); + methodTypes.parameterTypes, methodTypes.exceptions, bindings, typeBounds, firstLineNumber)); } else if ("".equals(name)) { - list.add(new ClassFileStaticInitializerDeclaration(bodyDeclaration, classFile, method, firstLineNumber)); + list.add(new ClassFileStaticInitializerDeclaration(bodyDeclaration, classFile, method, bindings, typeBounds, firstLineNumber)); } else { - ClassFileMethodDeclaration methodDeclaration; - TypeMaker.MethodTypes methodTypes = parser.parseMethodSignature(classFile, method); - list.add(methodDeclaration = new ClassFileMethodDeclaration( + ClassFileMethodDeclaration methodDeclaration = new ClassFileMethodDeclaration( bodyDeclaration, classFile, method, annotationReferences, name, methodTypes.typeParameters, methodTypes.returnedType, methodTypes.parameterTypes, methodTypes.exceptions, defaultAnnotationValue, - firstLineNumber)); + bindings, typeBounds, firstLineNumber); if ((classFile.getAccessFlags() & Constants.ACC_INTERFACE) != 0) { if (methodDeclaration.getFlags() == Constants.ACC_PUBLIC) { // For interfaces, add 'default' access flag on public methods methodDeclaration.setFlags(Declaration.FLAG_PUBLIC|Declaration.FLAG_DEFAULT); } } + list.add(methodDeclaration); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 5774ff52..bd40d83e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -53,6 +53,7 @@ public class ByteCodeParser { private TypeParametersToTypeArgumentsBinder typeParametersToTypeArgumentsBinder; private AttributeBootstrapMethods attributeBootstrapMethods; private ClassFileBodyDeclaration bodyDeclaration; + private Map typeBounds; private Type returnedType; public ByteCodeParser( @@ -61,10 +62,11 @@ public ByteCodeParser( this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; this.internalTypeName = classFile.getInternalTypeName(); - this.typeParametersToTypeArgumentsBinder = new TypeParametersToTypeArgumentsBinder(typeMaker, this.internalTypeName, bodyDeclaration, comd); + this.typeParametersToTypeArgumentsBinder = new TypeParametersToTypeArgumentsBinder(typeMaker, this.internalTypeName, comd); this.attributeBootstrapMethods = classFile.getAttribute("BootstrapMethods"); this.bodyDeclaration = bodyDeclaration; this.returnedType = comd.getReturnedType(); + this.typeBounds = comd.getTypeBounds(); } @SuppressWarnings("unchecked") @@ -736,7 +738,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(localVariable.getType(), valueRef); - localVariable.typeOnRight(valueRef.getType()); + localVariable.typeOnRight(typeBounds, valueRef.getType()); ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); Expression oldValueRef = valueRef; @@ -1531,7 +1529,7 @@ private void createAssignment(Statements statements, DefaultStack st } @SuppressWarnings("unchecked") - private static void parseIINC(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, int count) { + private void parseIINC(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, int count) { Expression expression; if (!stack.isEmpty()) { @@ -1777,20 +1775,20 @@ private Expression newNewExpression(int lineNumber, String internalTypeName) { * See "Additive Operators (+ and -) for Numeric Types": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2 * See "Shift Operators": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19 */ - private static Expression newIntegerBinaryOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + private Expression newIntegerBinaryOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { Class leftClass = leftExpression.getClass(); Class rightClass = rightExpression.getClass(); if (leftClass == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable leftVariable = ((ClassFileLocalVariableReferenceExpression)leftExpression).getLocalVariable(); - leftVariable.typeOnLeft(MAYBE_BYTE_TYPE); + leftVariable.typeOnLeft(typeBounds, MAYBE_BYTE_TYPE); } if (rightClass == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - rightVariable.typeOnLeft(MAYBE_BYTE_TYPE); + rightVariable.typeOnLeft(typeBounds, MAYBE_BYTE_TYPE); } return new BinaryOperatorExpression(lineNumber, TYPE_INT, leftExpression, operator, rightExpression, priority); @@ -1800,7 +1798,7 @@ private static Expression newIntegerBinaryOperatorExpression(int lineNumber, Exp * Operators = { "&", "|", "^" } * See "Binary Numeric Promotion": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.22.1 */ - private static Expression newIntegerOrBooleanBinaryOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + private Expression newIntegerOrBooleanBinaryOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { Class leftClass = leftExpression.getClass(); Class rightClass = rightExpression.getClass(); Type type = TYPE_INT; @@ -1811,9 +1809,9 @@ private static Expression newIntegerOrBooleanBinaryOperatorExpression(int lineNu if (rightClass == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - if (leftVariable.isAssignableFrom(TYPE_BOOLEAN) || rightVariable.isAssignableFrom(TYPE_BOOLEAN)) { - leftVariable.variableOnRight(rightVariable); - rightVariable.variableOnLeft(leftVariable); + if (leftVariable.isAssignableFrom(typeBounds, TYPE_BOOLEAN) || rightVariable.isAssignableFrom(typeBounds, TYPE_BOOLEAN)) { + leftVariable.variableOnRight(typeBounds, rightVariable); + rightVariable.variableOnLeft(typeBounds, leftVariable); if ((leftVariable.getType() == TYPE_BOOLEAN) || (rightVariable.getType() == TYPE_BOOLEAN)) { type = TYPE_BOOLEAN; @@ -1821,7 +1819,7 @@ private static Expression newIntegerOrBooleanBinaryOperatorExpression(int lineNu } } else { if (rightExpression.getType() == TYPE_BOOLEAN) { - leftVariable.typeOnRight(type = TYPE_BOOLEAN); + leftVariable.typeOnRight(typeBounds, type = TYPE_BOOLEAN); } } } else { @@ -1829,7 +1827,7 @@ private static Expression newIntegerOrBooleanBinaryOperatorExpression(int lineNu if (leftExpression.getType() == TYPE_BOOLEAN) { AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - rightVariable.typeOnRight(type = TYPE_BOOLEAN); + rightVariable.typeOnRight(typeBounds, type = TYPE_BOOLEAN); } } } @@ -1851,13 +1849,13 @@ private Expression newIntegerOrBooleanComparisonOperatorExpression(int lineNumbe if (rightClass == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - if (leftVariable.isAssignableFrom(TYPE_BOOLEAN) || rightVariable.isAssignableFrom(TYPE_BOOLEAN)) { - leftVariable.variableOnRight(rightVariable); - rightVariable.variableOnLeft(leftVariable); + if (leftVariable.isAssignableFrom(typeBounds, TYPE_BOOLEAN) || rightVariable.isAssignableFrom(typeBounds, TYPE_BOOLEAN)) { + leftVariable.variableOnRight(typeBounds, rightVariable); + rightVariable.variableOnLeft(typeBounds, leftVariable); } } else { if (rightExpression.getType() == TYPE_BOOLEAN) { - leftVariable.typeOnRight(TYPE_BOOLEAN); + leftVariable.typeOnRight(typeBounds, TYPE_BOOLEAN); } } } else { @@ -1865,7 +1863,7 @@ private Expression newIntegerOrBooleanComparisonOperatorExpression(int lineNumbe if (leftExpression.getType() == TYPE_BOOLEAN) { AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - rightVariable.typeOnRight(TYPE_BOOLEAN); + rightVariable.typeOnRight(typeBounds, TYPE_BOOLEAN); } } } @@ -1880,43 +1878,43 @@ private Expression newIntegerOrBooleanComparisonOperatorExpression(int lineNumbe * Operators = { "==", "!=" } * See "Numerical Equality Operators == and !=": https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.21.1 */ - private static Expression newIntegerComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { + private Expression newIntegerComparisonOperatorExpression(int lineNumber, Expression leftExpression, String operator, Expression rightExpression, int priority) { Class leftClass = leftExpression.getClass(); Class rightClass = rightExpression.getClass(); if (leftClass == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable leftVariable = ((ClassFileLocalVariableReferenceExpression)leftExpression).getLocalVariable(); - leftVariable.typeOnLeft(MAYBE_BYTE_TYPE); + leftVariable.typeOnLeft(typeBounds, MAYBE_BYTE_TYPE); } if (rightClass == ClassFileLocalVariableReferenceExpression.class) { AbstractLocalVariable rightVariable = ((ClassFileLocalVariableReferenceExpression)rightExpression).getLocalVariable(); - rightVariable.typeOnLeft(MAYBE_BYTE_TYPE); + rightVariable.typeOnLeft(typeBounds, MAYBE_BYTE_TYPE); } return new BinaryOperatorExpression(lineNumber, TYPE_BOOLEAN, leftExpression, operator, rightExpression, priority); } - private static Expression newPreArithmeticOperatorExpression(int lineNumber, String operator, Expression expression) { + private Expression newPreArithmeticOperatorExpression(int lineNumber, String operator, Expression expression) { reduceIntegerLocalVariableType(expression); return new PreOperatorExpression(lineNumber, operator, expression); } - private static Expression newPostArithmeticOperatorExpression(int lineNumber, Expression expression, String operator) { + private Expression newPostArithmeticOperatorExpression(int lineNumber, Expression expression, String operator) { reduceIntegerLocalVariableType(expression); return new PostOperatorExpression(lineNumber, expression, operator); } - private static void reduceIntegerLocalVariableType(Expression expression) { + private void reduceIntegerLocalVariableType(Expression expression) { if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { ClassFileLocalVariableReferenceExpression lvre = (ClassFileLocalVariableReferenceExpression)expression; if (lvre.getLocalVariable().getClass() == PrimitiveLocalVariable.class) { PrimitiveLocalVariable plv = (PrimitiveLocalVariable)lvre.getLocalVariable(); - if (plv.isAssignableFrom(MAYBE_BOOLEAN_TYPE)) { - plv.typeOnRight(MAYBE_BYTE_TYPE); + if (plv.isAssignableFrom(typeBounds, MAYBE_BOOLEAN_TYPE)) { + plv.typeOnRight(typeBounds, MAYBE_BYTE_TYPE); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index bf14838e..5ca5e96c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import static org.jd.core.v1.model.javasyntax.declaration.MethodDeclaration.*; @@ -35,6 +36,7 @@ public class LocalVariableMaker { protected AbstractLocalVariable[] localVariableCache; protected TypeMaker typeMaker; + protected Map typeBounds; protected FormalParameters formalParameters; protected PopulateBlackListNamesVisitor populateBlackListNamesVisitor = new PopulateBlackListNamesVisitor(blackListNames); @@ -48,6 +50,7 @@ public LocalVariableMaker(TypeMaker typeMaker, ClassFileConstructorOrMethodDecla Method method = comd.getMethod(); this.typeMaker = typeMaker; + this.typeBounds = comd.getTypeBounds(); this.createParameterVisitor = new CreateParameterVisitor(typeMaker); this.createLocalVariableVisitor = new CreateLocalVariableVisitor(typeMaker); @@ -298,7 +301,7 @@ public AbstractLocalVariable getLocalVariable(int index, int offset) { } } else if (lv.getFrame() != currentFrame) { Frame frame = searchCommonParentFrame(lv.getFrame(), currentFrame); - frame.mergeLocalVariable(this, lv); + frame.mergeLocalVariable(typeBounds, this, lv); if (lv.getFrame() != frame) { lv.getFrame().removeLocalVariable(lv); @@ -362,7 +365,7 @@ public boolean isCompatible(AbstractLocalVariable lv, Type valueType) { return false; } - public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, Type valueType) { + public AbstractLocalVariable getLocalVariableInAssignment(Map typeBounds, int index, int offset, Type valueType) { AbstractLocalVariable lv = searchLocalVariable(index, offset); if (lv == null) { @@ -370,9 +373,9 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, createLocalVariableVisitor.init(index, offset); valueType.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); - } else if (lv.isAssignableFrom(valueType) || isCompatible(lv, valueType)) { + } else if (lv.isAssignableFrom(typeBounds, valueType) || isCompatible(lv, valueType)) { // Assignable, reduce type - lv.typeOnRight(valueType); + lv.typeOnRight(typeBounds, valueType); } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueType)) { // Not assignable -> Create a new local variable createLocalVariableVisitor.init(index, offset); @@ -386,7 +389,7 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, return lv; } - public AbstractLocalVariable getLocalVariableInCastAssignment(int index, int offset, Type castType, Type valueType) { + public AbstractLocalVariable getLocalVariableInCastAssignment(Map typeBounds, int index, int offset, Type castType, Type valueType) { AbstractLocalVariable lv = searchLocalVariable(index, offset); if (lv == null) { @@ -394,12 +397,12 @@ public AbstractLocalVariable getLocalVariableInCastAssignment(int index, int off createLocalVariableVisitor.init(index, offset); valueType.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); - } else if (lv.isAssignableFrom(castType) || isCompatible(lv, castType)) { + } else if (lv.isAssignableFrom(typeBounds, castType) || isCompatible(lv, castType)) { // Assignable, reduce type - lv.typeOnRight(castType); - } else if (lv.isAssignableFrom(valueType) || isCompatible(lv, valueType)) { + lv.typeOnRight(typeBounds, castType); + } else if (lv.isAssignableFrom(typeBounds, valueType) || isCompatible(lv, valueType)) { // Assignable, reduce type - lv.typeOnRight(valueType); + lv.typeOnRight(typeBounds, valueType); } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueType)) { // Not assignable -> Create a new local variable createLocalVariableVisitor.init(index, offset); @@ -438,7 +441,7 @@ public AbstractLocalVariable getLocalVariableInNullAssignment(int index, int off return lv; } - public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, AbstractLocalVariable valueLocalVariable) { + public AbstractLocalVariable getLocalVariableInAssignment(Map typeBounds, int index, int offset, AbstractLocalVariable valueLocalVariable) { AbstractLocalVariable lv = searchLocalVariable(index, offset); if (lv == null) { @@ -446,7 +449,7 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, createLocalVariableVisitor.init(index, offset); valueLocalVariable.accept(createLocalVariableVisitor); lv = createLocalVariableVisitor.getLocalVariable(); - } else if (lv.isAssignableFrom(valueLocalVariable) || isCompatible(lv, valueLocalVariable.getType())) { + } else if (lv.isAssignableFrom(typeBounds, valueLocalVariable) || isCompatible(lv, valueLocalVariable.getType())) { // Assignable } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueLocalVariable.getType())) { // Not assignable -> Create a new local variable @@ -455,7 +458,7 @@ public AbstractLocalVariable getLocalVariableInAssignment(int index, int offset, lv = createLocalVariableVisitor.getLocalVariable(); } - lv.variableOnRight(valueLocalVariable); + lv.variableOnRight(typeBounds, valueLocalVariable); lv.setToOffset(offset); store(lv); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index f3ce3c3e..be1b163f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -9,6 +9,7 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.GenericType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; @@ -29,6 +30,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.ListIterator; +import java.util.Map; import static org.jd.core.v1.model.javasyntax.statement.ContinueStatement.CONTINUE; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_ITERABLE; @@ -36,8 +38,10 @@ public class LoopStatementMaker { protected static final RemoveLastContinueStatementVisitor REMOVE_LAST_CONTINUE_STATEMENT_VISITOR = new RemoveLastContinueStatementVisitor(); - public static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements, Statements jumps) { - Statement loop = makeLoop(localVariableMaker, loopBasicBlock, statements, condition, subStatements); + public static Statement makeLoop( + Map typeBounds, LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, + Statements statements, Expression condition, Statements subStatements, Statements jumps) { + Statement loop = makeLoop(typeBounds, localVariableMaker, loopBasicBlock, statements, condition, subStatements); int continueOffset = loopBasicBlock.getSub1().getFromOffset(); int breakOffset = loopBasicBlock.getNext().getFromOffset(); @@ -48,16 +52,18 @@ public static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlo return makeLabels(loopBasicBlock.getIndex(), continueOffset, breakOffset, loop, jumps); } - protected static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements) { + protected static Statement makeLoop( + Map typeBounds, LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, + Statements statements, Expression condition, Statements subStatements) { subStatements.accept(REMOVE_LAST_CONTINUE_STATEMENT_VISITOR); - Statement statement = makeForEachArray(localVariableMaker, statements, condition, subStatements); + Statement statement = makeForEachArray(typeBounds, localVariableMaker, statements, condition, subStatements); if (statement != null) { return statement; } - statement = makeForEachList(localVariableMaker, statements, condition, subStatements); + statement = makeForEachList(typeBounds, localVariableMaker, statements, condition, subStatements); if (statement != null) { return statement; @@ -345,7 +351,9 @@ protected static Statement createForStatementWithoutLineNumber(BasicBlock basicB return new WhileStatement(condition, subStatements); } - protected static Statement makeForEachArray(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { + protected static Statement makeForEachArray( + Map typeBounds, LocalVariableMaker localVariableMaker, Statements statements, + Expression condition, Statements subStatements) { if (condition == null) { return null; } @@ -510,11 +518,11 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake Type type = arrayType.createType(arrayType.getDimension()-1); if (ObjectType.TYPE_OBJECT.equals(item.getType())) { - ((ObjectLocalVariable)item).setType(type); + ((ObjectLocalVariable)item).setType(typeBounds, type); } else if (item.getType().isGeneric()) { ((GenericLocalVariable)item).setType((GenericType)type); } else { - item.typeOnRight(type); + item.typeOnRight(typeBounds, type); } localVariableMaker.removeLocalVariable(syntheticArray); @@ -524,7 +532,9 @@ protected static Statement makeForEachArray(LocalVariableMaker localVariableMake return new ClassFileForEachStatement(item, array, subStatements); } - protected static Statement makeForEachList(LocalVariableMaker localVariableMaker, Statements statements, Expression condition, Statements subStatements) { + protected static Statement makeForEachList( + Map typeBounds, LocalVariableMaker localVariableMaker, Statements statements, + Expression condition, Statements subStatements) { if (condition == null) { return null; } @@ -660,11 +670,11 @@ protected static Statement makeForEachList(LocalVariableMaker localVariableMaker if (type != null) { if (ObjectType.TYPE_OBJECT.equals(item.getType())) { - ((ObjectLocalVariable) item).setType(type); + ((ObjectLocalVariable) item).setType(typeBounds, type); } else if (item.getType().isGeneric()) { ((GenericLocalVariable) item).setType((GenericType) type); } else { - item.typeOnRight(type); + item.typeOnRight(typeBounds, type); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index d4b42fe8..99d7e27d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -15,6 +15,7 @@ import org.jd.core.v1.model.javasyntax.declaration.MethodDeclaration; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.BaseType; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.PrimitiveType; import org.jd.core.v1.model.javasyntax.type.Type; @@ -41,12 +42,14 @@ import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; + public class StatementMaker { protected static final SwitchCaseComparator SWITCH_CASE_COMPARATOR = new SwitchCaseComparator(); protected static final NullExpression FINALLY_EXCEPTION_EXPRESSION = new NullExpression(new ObjectType("java/lang/Exception", "java.lang.Exception", "Exception")); protected static final MergeTryWithResourcesStatementVisitor MERGE_TRY_WITH_RESOURCES_STATEMENT_VISITOR = new MergeTryWithResourcesStatementVisitor(); protected TypeMaker typeMaker; + protected Map typeBounds; protected LocalVariableMaker localVariableMaker; protected ByteCodeParser byteCodeParser; protected int majorVersion; @@ -65,6 +68,7 @@ public StatementMaker( TypeMaker typeMaker, LocalVariableMaker localVariableMaker, ClassFile classFile, ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { this.typeMaker = typeMaker; + this.typeBounds = comd.getTypeBounds(); this.localVariableMaker = localVariableMaker; this.majorVersion = classFile.getMajorVersion(); this.internalTypeName = classFile.getInternalTypeName(); @@ -622,7 +626,8 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st // 'while' or 'for' loop makeStatements(watchdog, ifBB.getCondition(), statements, jumps); statements.add(LoopStatementMaker.makeLoop( - localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateStatements), jumps)); + typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), + makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateStatements), jumps)); makeStatements(watchdog, basicBlock.getNext(), statements, jumps); return; } @@ -641,7 +646,9 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st // 'while' or 'for' loop ifBB.getCondition().inverseCondition(); makeStatements(watchdog, ifBB.getCondition(), statements, jumps); - statements.add(LoopStatementMaker.makeLoop(localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getNext(), statements, jumps, updateStatements), jumps)); + statements.add(LoopStatementMaker.makeLoop( + typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), + makeSubStatements(watchdog, ifBB.getNext(), statements, jumps, updateStatements), jumps)); } makeStatements(watchdog, basicBlock.getNext(), statements, jumps); @@ -895,9 +902,9 @@ protected TernaryOperatorExpression newTernaryOperatorExpression(int lineNumber, ObjectType ot1 = (ObjectType)expressionTrueType; ObjectType ot2 = (ObjectType)expressionFalseType; - if (typeMaker.isAssignable(ot1, ot2)) { + if (typeMaker.isAssignable(typeBounds, ot1, ot2)) { type = getTernaryOperatorExpressionType(ot1, ot2); - } else if (typeMaker.isAssignable(ot2, ot1)) { + } else if (typeMaker.isAssignable(typeBounds, ot2, ot1)) { type = getTernaryOperatorExpressionType(ot2, ot1); } else { type = TYPE_OBJECT; @@ -914,9 +921,9 @@ protected Type getTernaryOperatorExpressionType(ObjectType ot1, ObjectType ot2) return ot1; } else if (ot2.getTypeArguments() == null) { return ot1.createType(null); - } else if (ot1.isTypeArgumentAssignableFrom(ot2)) { + } else if (ot1.isTypeArgumentAssignableFrom(typeBounds, ot2)) { return ot1; - } else if (ot2.isTypeArgumentAssignableFrom(ot1)) { + } else if (ot2.isTypeArgumentAssignableFrom(typeBounds, ot1)) { return ot1.createType(ot2.getTypeArguments()); } else { return ot1.createType(null); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index 863367ab..bc2983f1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; @@ -875,7 +876,7 @@ public ObjectType searchSuperParameterizedType(ObjectType superObjectType, Objec } } - public boolean isAssignable(ObjectType left, ObjectType right) { + public boolean isAssignable(Map typeBounds, ObjectType left, ObjectType right) { if ((left == TYPE_UNDEFINED_OBJECT) || left.equals(TYPE_OBJECT) || left.equals(right)) { return true; } else if ((left.getDimension() > 0) || (right.getDimension() > 0)) { @@ -889,7 +890,7 @@ public boolean isAssignable(ObjectType left, ObjectType right) { if ((left.getTypeArguments() == null) || (ot.getTypeArguments() == null)) { return true; } else { - return left.getTypeArguments().isTypeArgumentAssignableFrom(ot.getTypeArguments()); + return left.getTypeArguments().isTypeArgumentAssignableFrom(typeBounds, ot.getTypeArguments()); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 94910e37..aa72f840 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -35,40 +35,13 @@ public class TypeParametersToTypeArgumentsBinder { protected Map contextualBindings; protected Map contextualTypeBounds; - public TypeParametersToTypeArgumentsBinder( - TypeMaker typeMaker, String internalTypeName, ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { + public TypeParametersToTypeArgumentsBinder(TypeMaker typeMaker, String internalTypeName, ClassFileConstructorOrMethodDeclaration comd) { this.typeMaker = typeMaker; this.internalTypeName = internalTypeName; this.staticMethod = ((comd.getFlags() & FLAG_STATIC) != 0); this.populateBindingsWithTypeArgumentVisitor = new PopulateBindingsWithTypeArgumentVisitor(typeMaker); - - if (this.staticMethod) { - this.contextualBindings = Collections.emptyMap(); - this.contextualTypeBounds = Collections.emptyMap(); - } else { - this.contextualBindings = bodyDeclaration.getBindings(); - this.contextualTypeBounds = bodyDeclaration.getTypeBounds(); - } - - if (comd.getTypeParameters() != null) { - HashMap bindings = new HashMap<>(); - Map typeBounds = new HashMap<>(); - - bindings.putAll(this.contextualBindings); - typeBounds.putAll(this.contextualTypeBounds); - - populateBindingsWithTypeParameterVisitor.init(bindings, typeBounds); - comd.getTypeParameters().accept(populateBindingsWithTypeParameterVisitor); - - for (HashMap.Entry entry : bindings.entrySet()) { - if (entry.getValue() == null) { - entry.setValue(new GenericType(entry.getKey())); - } - } - - this.contextualBindings = bindings; - this.contextualTypeBounds = typeBounds; - } + this.contextualBindings = comd.getBindings(); + this.contextualTypeBounds = comd.getTypeBounds(); } public ClassFileConstructorInvocationExpression newConstructorInvocationExpression( @@ -537,7 +510,7 @@ public void visit(MethodInvocationExpression expression) { public void visit(LocalVariableReferenceExpression expression) { if (!type.isPrimitive()) { AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); - localVariable.typeOnLeft(checkTypeArguments(type, localVariable)); + localVariable.typeOnLeft(contextualTypeBounds, checkTypeArguments(type, localVariable)); } } @@ -567,7 +540,7 @@ public void visit(CastExpression expression) { if (expressionExpressionObjectType.getTypeArguments() == null) { expression.setType(objectType); - } else if (objectType.getTypeArguments().isTypeArgumentAssignableFrom(expressionExpressionObjectType.getTypeArguments())) { + } else if (objectType.getTypeArguments().isTypeArgumentAssignableFrom(contextualTypeBounds, expressionExpressionObjectType.getTypeArguments())) { expression.setType(objectType); } } else if (expressionExpressionType.isGeneric()) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index 295badab..b95456a5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -14,16 +14,23 @@ import org.jd.core.v1.model.javasyntax.reference.ObjectReference; import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileMethodDeclaration; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileStaticInitializerDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; import org.jd.core.v1.util.DefaultList; +import java.util.Map; + import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; public class AddCastExpressionVisitor extends AbstractJavaSyntaxVisitor { protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); protected TypeMaker typeMaker; + protected Map typeBounds; protected Type returnedType; protected Type type; @@ -31,6 +38,19 @@ public AddCastExpressionVisitor(TypeMaker typeMaker) { this.typeMaker = typeMaker; } + @Override + public void visit(BodyDeclaration declaration) { + BaseMemberDeclaration memberDeclarations = declaration.getMemberDeclarations(); + + if (memberDeclarations != null) { + Map tb = typeBounds; + + typeBounds = ((ClassFileBodyDeclaration)declaration).getTypeBounds(); + memberDeclarations.accept(this); + typeBounds = tb; + } + } + @Override public void visit(FieldDeclaration declaration) { Type t = type; @@ -59,9 +79,31 @@ public void visit(FieldDeclarator declarator) { } } + + @Override + public void visit(StaticInitializerDeclaration declaration) { + BaseStatement statements = declaration.getStatements(); + + if (statements != null) { + Map tb = typeBounds; + + typeBounds = ((ClassFileStaticInitializerDeclaration)declaration).getTypeBounds(); + statements.accept(this); + typeBounds = tb; + } + } + @Override public void visit(ConstructorDeclaration declaration) { - safeAccept(declaration.getStatements()); + BaseStatement statements = declaration.getStatements(); + + if (statements != null) { + Map tb = typeBounds; + + typeBounds = ((ClassFileConstructorDeclaration)declaration).getTypeBounds(); + statements.accept(this); + typeBounds = tb; + } } @Override @@ -69,10 +111,13 @@ public void visit(MethodDeclaration declaration) { BaseStatement statements = declaration.getStatements(); if (statements != null) { + Map tb = typeBounds; Type t = returnedType; + typeBounds = ((ClassFileMethodDeclaration)declaration).getTypeBounds(); returnedType = declaration.getReturnedType(); statements.accept(this); + typeBounds = tb; returnedType = t; } } @@ -280,12 +325,12 @@ private Expression updateExpression(Type type, Expression expression) { ObjectType objectType = (ObjectType) type; ObjectType expressionObjectType = (ObjectType) expressionType; - if (!typeMaker.isAssignable(objectType, expressionObjectType)) { + if (!typeMaker.isAssignable(typeBounds, objectType, expressionObjectType)) { BaseTypeArgument ta1 = objectType.getTypeArguments(); BaseTypeArgument ta2 = expressionObjectType.getTypeArguments(); Type t = type; - if ((ta1 != null) && (ta2 != null) && !ta1.isTypeArgumentAssignableFrom(ta2)) { + if ((ta1 != null) && (ta2 != null) && !ta1.isTypeArgumentAssignableFrom(typeBounds, ta2)) { // Incompatible typeArgument arguments => Uses raw typeArgument t = objectType.createType(null); } @@ -306,7 +351,7 @@ private Expression updateExpression(Type type, Expression expression) { CastExpression ce = (CastExpression)expression; Type ceExpressionType = ce.getExpression().getType(); - if (type.isObject() && ceExpressionType.isObject() && typeMaker.isAssignable((ObjectType)type, (ObjectType)ceExpressionType)) { + if (type.isObject() && ceExpressionType.isObject() && typeMaker.isAssignable(typeBounds, (ObjectType)type, (ObjectType)ceExpressionType)) { // Remove cast expression expression = ce.getExpression(); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java index 39e574e4..565ae2b6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java @@ -76,8 +76,8 @@ public void visit(TypeArguments arguments) { ObjectType ot1 = (ObjectType)t1; ObjectType ot2 = (ObjectType)t2.createType(t2.getDimension() - type.getDimension()); - if (!typeMaker.isAssignable(ot1, ot2)) { - if (typeMaker.isAssignable(ot2, ot1)) { + if (!typeMaker.isAssignable(typeBounds, ot1, ot2)) { + if (typeMaker.isAssignable(typeBounds, ot2, ot1)) { bindings.put(typeName, checkTypeClassCheckDimensionAndReturnCurrentAsTypeArgument(type)); } else { bindings.put(typeName, WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); diff --git a/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java index 0703f04c..303c752e 100644 --- a/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java +++ b/src/test/java/org/jd/core/v1/MergeMembersUtilTest.java @@ -19,6 +19,7 @@ import org.junit.Test; import java.util.Arrays; +import java.util.Collections; import java.util.List; @SuppressWarnings("unchecked") @@ -235,16 +236,16 @@ protected DefaultList newMethods() { ClassFile classFile = null; Method method = new Method(0, "method", "()V", null, null); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "a", PrimitiveType.TYPE_VOID, null)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "b", PrimitiveType.TYPE_VOID, null)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "c", PrimitiveType.TYPE_VOID, null, 20)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "d", PrimitiveType.TYPE_VOID, null, 21)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "e", PrimitiveType.TYPE_VOID, null)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "f", PrimitiveType.TYPE_VOID, null)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "g", PrimitiveType.TYPE_VOID, null, 40)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "h", PrimitiveType.TYPE_VOID, null)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "i", PrimitiveType.TYPE_VOID, null)); - methods.add(new ClassFileMethodDeclaration(null, classFile, method, "j", PrimitiveType.TYPE_VOID, null)); + methods.add(newMethodDeclaration(classFile, method, "a")); + methods.add(newMethodDeclaration(classFile, method, "b")); + methods.add(newMethodDeclaration(classFile, method, "c", 20)); + methods.add(newMethodDeclaration(classFile, method, "d", 21)); + methods.add(newMethodDeclaration(classFile, method, "e")); + methods.add(newMethodDeclaration(classFile, method, "f")); + methods.add(newMethodDeclaration(classFile, method, "g", 40)); + methods.add(newMethodDeclaration(classFile, method, "h")); + methods.add(newMethodDeclaration(classFile, method, "i")); + methods.add(newMethodDeclaration(classFile, method, "j")); return methods; } @@ -262,4 +263,12 @@ protected DefaultList newInnerTypes(int lineNumber) return innerTypes; } + + protected static ClassFileMethodDeclaration newMethodDeclaration(ClassFile classFile, Method method, String name) { + return newMethodDeclaration(classFile, method, name, 0); + } + + protected static ClassFileMethodDeclaration newMethodDeclaration(ClassFile classFile, Method method, String name, int firstLineNumber) { + return new ClassFileMethodDeclaration(null, classFile, method, name, PrimitiveType.TYPE_VOID, null, Collections.emptyMap(), Collections.emptyMap(), firstLineNumber); + } } diff --git a/src/test/java/org/jd/core/v1/TypeMakerTest.java b/src/test/java/org/jd/core/v1/TypeMakerTest.java index 95e3f3a2..55fd0224 100644 --- a/src/test/java/org/jd/core/v1/TypeMakerTest.java +++ b/src/test/java/org/jd/core/v1/TypeMakerTest.java @@ -19,10 +19,7 @@ import org.junit.Test; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.PrimitiveIterator; +import java.util.*; public class TypeMakerTest extends TestCase { protected TypeMaker typeMaker = new TypeMaker(new ClassPathLoader()); @@ -137,7 +134,7 @@ public void testListIsAssignableFromArrayList() throws Exception { assertNotNull(parent); assertNotNull(child); - assertTrue(typeMaker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), parent, child)); } @Test @@ -147,7 +144,7 @@ public void testClassIsAssignableFromObject() throws Exception { assertNotNull(parent); assertNotNull(child); - assertFalse(typeMaker.isAssignable(parent, child)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), parent, child)); } @Test @@ -159,7 +156,7 @@ public void testObjectIsAssignableFromSafeNumberComparator() throws Exception { assertNotNull(parent); assertNotNull(child); - assertTrue(typeMaker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), parent, child)); } @Test @@ -171,7 +168,7 @@ public void testComparatorIsAssignableFromSafeNumberComparator() throws Exceptio assertNotNull(parent); assertNotNull(child); - assertTrue(typeMaker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), parent, child)); } @Test @@ -183,7 +180,7 @@ public void testNumberComparatorIsAssignableFromSafeNumberComparator() throws Ex assertNotNull(parent); assertNotNull(child); - assertTrue(typeMaker.isAssignable(parent, child)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), parent, child)); } @Test @@ -195,7 +192,7 @@ public void testOuterClassIsAssignableFromSimpleClass() throws Exception { assertNotNull(parent); assertNotNull(child); - assertFalse(typeMaker.isAssignable(parent, child)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), parent, child)); } @Test public void testListAssignment() throws Exception { @@ -206,10 +203,10 @@ public void testListAssignment() throws Exception { ObjectType ot2 = otList; // Valid: list1 = list2; - assertTrue(typeMaker.isAssignable(ot1, ot2)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); // Valid: list2 = list1; - assertTrue(typeMaker.isAssignable(ot2, ot1)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot2, ot1)); } @Test @@ -221,10 +218,10 @@ public void testListAndArrayListAssignment() throws Exception { ObjectType ot2 = otArrayList; // Valid: list1 = list2; - assertTrue(typeMaker.isAssignable(ot1, ot2)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); // Invalid: list2 = list1; - assertFalse(typeMaker.isAssignable(ot2, ot1)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot2, ot1)); } @Test @@ -236,10 +233,10 @@ public void testListNumberAndArrayListNumberAssignment() throws Exception { ObjectType ot2 = otArrayList.createType(otNumber); // Valid: list1 = list2; - assertTrue(typeMaker.isAssignable(ot1, ot2)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); // Invalid: list2 = list1; - assertFalse(typeMaker.isAssignable(ot2, ot1)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot2, ot1)); } @Test @@ -251,10 +248,10 @@ public void testListNumberAndListIntegerAssignment() throws Exception { ObjectType ot2 = otList.createType(otInteger); // Invalid: list1 = list2; - assertFalse(typeMaker.isAssignable(ot1, ot2)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); // Invalid: list2 = list1; - assertFalse(typeMaker.isAssignable(ot2, ot1)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot2, ot1)); } @Test @@ -266,10 +263,10 @@ public void testListNumberAndListExtendsNumberAssignment() throws Exception { ObjectType ot2 = otList.createType(new WildcardExtendsTypeArgument(otNumber)); // Invalid: list1 = list2; - assertFalse(typeMaker.isAssignable(ot1, ot2)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); // Valid: list2 = list1; - assertTrue(typeMaker.isAssignable(ot2, ot1)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot2, ot1)); } @Test @@ -281,10 +278,10 @@ public void testListNumberAndListSuperNumberAssignment() throws Exception { ObjectType ot2 = otList.createType(new WildcardSuperTypeArgument(otNumber)); // Invalid: list1 = list2; - assertFalse(typeMaker.isAssignable(ot1, ot2)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); // Valid: list2 = list1; - assertTrue(typeMaker.isAssignable(ot2, ot1)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot2, ot1)); } @Test @@ -296,10 +293,10 @@ public void testListNumberAndArrayListIntegerAssignment() throws Exception { ObjectType ot2 = otArrayList.createType(otInteger); // Invalid: list1 = list2; - assertFalse(typeMaker.isAssignable(ot1, ot2)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); // Invalid: list2 = list1; - assertFalse(typeMaker.isAssignable(ot2, ot1)); + assertFalse(typeMaker.isAssignable(Collections.emptyMap(), ot2, ot1)); } @Test @@ -315,7 +312,7 @@ public void testIteratorNumberAndPrimitiveIteratorNumberAssignment() throws Exce ObjectType ot2 = otPrimitiveIterator.createType(tas); // Valid: iterator1 = iterator2; - assertTrue(typeMaker.isAssignable(ot1, ot2)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); } @Test @@ -331,6 +328,6 @@ public void testIteratorNumberAndAbstractUntypedIteratorDecoratorNumberAssignmen ObjectType ot2 = otAbstractUntypedIteratorDecorator.createType(tas); // Valid: iterator1 = iterator2; - assertTrue(typeMaker.isAssignable(ot1, ot2)); + assertTrue(typeMaker.isAssignable(Collections.emptyMap(), ot1, ot2)); } } From 0bc5912c1ff62a18a20b693e9830b4ed56d3c612 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 16 Dec 2019 19:03:19 +0100 Subject: [PATCH 111/211] Fix syntax errors in decompiled sources --- .../javasyntax/AbstractJavaSyntaxVisitor.java | 2 +- .../declaration/ConstructorDeclaration.java | 10 +++---- .../ClassFileConstructorDeclaration.java | 4 +-- .../ClassFileMethodDeclaration.java | 4 +-- .../processor/ConvertClassFileProcessor.java | 4 +-- .../classfiletojavasyntax/util/TypeMaker.java | 16 +++++----- .../visitor/AddCastExpressionVisitor.java | 29 +++++++++++++++---- .../visitor/CompilationUnitVisitor.java | 6 ++-- .../org/jd/core/v1/SignatureParserTest.java | 14 ++++----- 9 files changed, 54 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java index f5e99ca1..df7c5e7a 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java @@ -68,7 +68,7 @@ public void visit(ConstructorInvocationExpression expression) { public void visit(ConstructorDeclaration declaration) { safeAccept(declaration.getAnnotationReferences()); safeAccept(declaration.getFormalParameters()); - safeAccept(declaration.getExceptions()); + safeAccept(declaration.getExceptionTypes()); safeAccept(declaration.getStatements()); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java index 0621ab1f..27f4d9c7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java @@ -17,7 +17,7 @@ public class ConstructorDeclaration implements MemberDeclaration { protected int flags; protected BaseTypeParameter typeParameters; protected BaseFormalParameter formalParameters; - protected BaseType exceptions; + protected BaseType exceptionTypes; protected String descriptor; protected BaseStatement statements; @@ -28,12 +28,12 @@ public ConstructorDeclaration(int flags, BaseFormalParameter formalParameters, S this.statements = statements; } - public ConstructorDeclaration(BaseAnnotationReference annotationReferences, int flags, BaseTypeParameter typeParameters, BaseFormalParameter formalParameters, BaseType exceptions, String descriptor, BaseStatement statements) { + public ConstructorDeclaration(BaseAnnotationReference annotationReferences, int flags, BaseTypeParameter typeParameters, BaseFormalParameter formalParameters, BaseType exceptionTypes, String descriptor, BaseStatement statements) { this.annotationReferences = annotationReferences; this.flags = flags; this.typeParameters = typeParameters; this.formalParameters = formalParameters; - this.exceptions = exceptions; + this.exceptionTypes = exceptionTypes; this.descriptor = descriptor; this.statements = statements; } @@ -54,8 +54,8 @@ public BaseFormalParameter getFormalParameters() { return formalParameters; } - public BaseType getExceptions() { - return exceptions; + public BaseType getExceptionTypes() { + return exceptionTypes; } public String getDescriptor() { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java index c3e5a423..fdb70f4f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java @@ -31,9 +31,9 @@ public class ClassFileConstructorDeclaration extends ConstructorDeclaration impl public ClassFileConstructorDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, BaseAnnotationReference annotationReferences, - BaseTypeParameter typeParameters, BaseType parameterTypes, BaseType exceptions, Map bindings, + BaseTypeParameter typeParameters, BaseType parameterTypes, BaseType exceptionTypes, Map bindings, Map typeBounds, int firstLineNumber) { - super(annotationReferences, method.getAccessFlags(), typeParameters, null, exceptions, method.getDescriptor(), null); + super(annotationReferences, method.getAccessFlags(), typeParameters, null, exceptionTypes, method.getDescriptor(), null); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; this.method = method; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java index 217fff70..c7aa32be 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileMethodDeclaration.java @@ -59,10 +59,10 @@ public ClassFileMethodDeclaration( public ClassFileMethodDeclaration( ClassFileBodyDeclaration bodyDeclaration, ClassFile classFile, Method method, BaseAnnotationReference annotationReferences, - String name, BaseTypeParameter typeParameters, Type returnedType, BaseType parameterTypes, BaseType exceptions, + String name, BaseTypeParameter typeParameters, Type returnedType, BaseType parameterTypes, BaseType exceptionTypes, ElementValue defaultAnnotationValue, Map bindings, Map typeBounds, int firstLineNumber) { - super(annotationReferences, method.getAccessFlags(), name, typeParameters, returnedType, null, exceptions, method.getDescriptor(), null, defaultAnnotationValue); + super(annotationReferences, method.getAccessFlags(), name, typeParameters, returnedType, null, exceptionTypes, method.getDescriptor(), null, defaultAnnotationValue); this.bodyDeclaration = bodyDeclaration; this.classFile = classFile; this.method = method; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index ac6ca2c1..389a0de8 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -220,13 +220,13 @@ protected List convertMethods(TypeMaker if ("".equals(name)) { list.add(new ClassFileConstructorDeclaration( bodyDeclaration, classFile, method, annotationReferences, methodTypes.typeParameters, - methodTypes.parameterTypes, methodTypes.exceptions, bindings, typeBounds, firstLineNumber)); + methodTypes.parameterTypes, methodTypes.exceptionTypes, bindings, typeBounds, firstLineNumber)); } else if ("".equals(name)) { list.add(new ClassFileStaticInitializerDeclaration(bodyDeclaration, classFile, method, bindings, typeBounds, firstLineNumber)); } else { ClassFileMethodDeclaration methodDeclaration = new ClassFileMethodDeclaration( bodyDeclaration, classFile, method, annotationReferences, name, methodTypes.typeParameters, - methodTypes.returnedType, methodTypes.parameterTypes, methodTypes.exceptions, defaultAnnotationValue, + methodTypes.returnedType, methodTypes.parameterTypes, methodTypes.exceptionTypes, defaultAnnotationValue, bindings, typeBounds, firstLineNumber); if ((classFile.getAccessFlags() & Constants.ACC_INTERFACE) != 0) { if (methodDeclaration.getFlags() == Constants.ACC_PUBLIC) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index bc2983f1..ea300aa6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -251,7 +251,7 @@ private MethodTypes parseMethodSignature(String descriptor, String signature, St mt.typeParameters = mtSignature.typeParameters; mt.parameterTypes = mtDescriptor.parameterTypes; mt.returnedType = mtSignature.returnedType; - mt.exceptions = mtSignature.exceptions; + mt.exceptionTypes = mtSignature.exceptionTypes; return mt; } else if (mtDescriptor.parameterTypes.size() == mtSignature.parameterTypes.size()) { @@ -266,7 +266,7 @@ private MethodTypes parseMethodSignature(String descriptor, String signature, St mt.typeParameters = mtSignature.typeParameters; mt.parameterTypes = parameterTypes; mt.returnedType = mtSignature.returnedType; - mt.exceptions = mtSignature.exceptions; + mt.exceptionTypes = mtSignature.exceptionTypes; return mt; } @@ -340,7 +340,7 @@ private MethodTypes parseMethodSignature(String signature, String[] exceptionTyp // Signature does not contain exceptions if (exceptionTypeNames != null) { if (exceptionTypeNames.length == 1) { - methodTypes.exceptions = makeFromInternalTypeName(exceptionTypeNames[0]); + methodTypes.exceptionTypes = makeFromInternalTypeName(exceptionTypeNames[0]); } else { UnmodifiableTypes list = new UnmodifiableTypes(exceptionTypeNames.length); @@ -348,14 +348,14 @@ private MethodTypes parseMethodSignature(String signature, String[] exceptionTyp list.add(makeFromInternalTypeName(exceptionTypeName)); } - methodTypes.exceptions = list; + methodTypes.exceptionTypes = list; } } } else { Type nextException = parseExceptionSignature(reader); if (nextException == null) { - methodTypes.exceptions = firstException; + methodTypes.exceptionTypes = firstException; } else { UnmodifiableTypes list = new UnmodifiableTypes(); @@ -366,7 +366,7 @@ private MethodTypes parseMethodSignature(String signature, String[] exceptionTyp nextException = parseExceptionSignature(reader); } while (nextException != null); - methodTypes.exceptions = list; + methodTypes.exceptionTypes = list; } } @@ -1336,7 +1336,7 @@ private MethodTypes loadMethodTypes(ObjectType objectType, String methodName, St newMethodTypes.returnedType = (Type)bindTypeParametersToTypeArgumentsVisitor.getType(); newMethodTypes.typeParameters = null; - newMethodTypes.exceptions = methodTypes.exceptions; + newMethodTypes.exceptionTypes = methodTypes.exceptionTypes; methodTypes = newMethodTypes; } @@ -1774,6 +1774,6 @@ public static class MethodTypes { public BaseTypeParameter typeParameters; public BaseType parameterTypes; public Type returnedType; - public BaseType exceptions; + public BaseType exceptionTypes; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index b95456a5..714ad19e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -32,6 +32,7 @@ public class AddCastExpressionVisitor extends AbstractJavaSyntaxVisitor { protected TypeMaker typeMaker; protected Map typeBounds; protected Type returnedType; + protected BaseType exceptionTypes; protected Type type; public AddCastExpressionVisitor(TypeMaker typeMaker) { @@ -99,10 +100,13 @@ public void visit(ConstructorDeclaration declaration) { if (statements != null) { Map tb = typeBounds; + BaseType et = exceptionTypes; typeBounds = ((ClassFileConstructorDeclaration)declaration).getTypeBounds(); + exceptionTypes = declaration.getExceptionTypes(); statements.accept(this); typeBounds = tb; + exceptionTypes = et; } } @@ -112,13 +116,16 @@ public void visit(MethodDeclaration declaration) { if (statements != null) { Map tb = typeBounds; - Type t = returnedType; + Type rt = returnedType; + BaseType et = exceptionTypes; typeBounds = ((ClassFileMethodDeclaration)declaration).getTypeBounds(); returnedType = declaration.getReturnedType(); + exceptionTypes = declaration.getExceptionTypes(); statements.accept(this); typeBounds = tb; - returnedType = t; + returnedType = rt; + exceptionTypes = et; } } @@ -127,18 +134,30 @@ public void visit(LambdaIdentifiersExpression expression) { BaseStatement statements = expression.getStatements(); if (statements != null) { - Type t = returnedType; + Type rt = returnedType; returnedType = expression.getReturnedType(); statements.accept(this); - returnedType = t; + returnedType = rt; } } - @Override public void visit(ReturnExpressionStatement statement) { + @Override + public void visit(ReturnExpressionStatement statement) { statement.setExpression(updateExpression(returnedType, statement.getExpression())); } + @Override + public void visit(ThrowStatement statement) { + if ((exceptionTypes != null) && (exceptionTypes.size() == 1)) { + Type exceptionType = exceptionTypes.getFirst(); + + if (exceptionType.isGeneric() && !statement.getExpression().getType().equals(exceptionType)) { + statement.setExpression(addCastExpression(exceptionType, statement.getExpression())); + } + } + } + @Override public void visit(LocalVariableDeclaration declaration) { Type t = type; diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 04e31f6b..2c3964ff 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -368,13 +368,13 @@ public void visit(ConstructorDeclaration declaration) { tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); } - BaseType exceptions = declaration.getExceptions(); + BaseType exceptionTypes = declaration.getExceptionTypes(); - if (exceptions != null) { + if (exceptionTypes != null) { tokens.add(TextToken.SPACE); tokens.add(THROWS); tokens.add(TextToken.SPACE); - exceptions.accept(this); + exceptionTypes.accept(this); } BaseStatement statements = declaration.getStatements(); diff --git a/src/test/java/org/jd/core/v1/SignatureParserTest.java b/src/test/java/org/jd/core/v1/SignatureParserTest.java index 925694c6..5d0fbb0d 100644 --- a/src/test/java/org/jd/core/v1/SignatureParserTest.java +++ b/src/test/java/org/jd/core/v1/SignatureParserTest.java @@ -102,7 +102,7 @@ public void testAnnotatedClass() throws Exception { Assert.assertEquals("int", source); // Check exceptions - assertNull(methodTypes.exceptions); + assertNull(methodTypes.exceptionTypes); // Check method 'ping' // public void ping(String host) throws UnknownHostException, UnsatisfiedLinkError @@ -133,10 +133,10 @@ public void testAnnotatedClass() throws Exception { Assert.assertEquals("void", source); // Check exceptions - assertNotNull(methodTypes.exceptions); + assertNotNull(methodTypes.exceptionTypes); visitor.reset(); - methodTypes.exceptions.accept(visitor); + methodTypes.exceptionTypes.accept(visitor); source = visitor.toString(); Assert.assertEquals("java.net.UnknownHostException, java.lang.UnsatisfiedLinkError", source); @@ -248,10 +248,10 @@ public void testGenericClass() throws Exception { Assert.assertEquals("java.util.List", source); // Check exceptions - assertNotNull(methodTypes.exceptions); + assertNotNull(methodTypes.exceptionTypes); visitor.reset(); - methodTypes.exceptions.accept(visitor); + methodTypes.exceptionTypes.accept(visitor); source = visitor.toString(); Assert.assertEquals("java.security.InvalidParameterException, java.lang.ClassCastException", source); @@ -290,10 +290,10 @@ public void testGenericClass() throws Exception { Assert.assertEquals("java.util.List", source); // Check exceptions - assertNotNull(methodTypes.exceptions); + assertNotNull(methodTypes.exceptionTypes); visitor.reset(); - methodTypes.exceptions.accept(visitor); + methodTypes.exceptionTypes.accept(visitor); source = visitor.toString(); Assert.assertEquals("T2, java.security.InvalidParameterException", source); From 6968f994e36e2c6d31f2fcb06260d450eb5f3f8b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 17 Dec 2019 11:24:21 +0100 Subject: [PATCH 112/211] Fix syntax errors in decompiled sources --- build.gradle | 6 +- .../classfiletojavasyntax/util/TypeMaker.java | 63 ++++++++++++- .../visitor/AddCastExpressionVisitor.java | 89 +++++++++++-------- 3 files changed, 115 insertions(+), 43 deletions(-) diff --git a/build.gradle b/build.gradle index ea554a29..8cd1311d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,10 +5,10 @@ apply plugin: 'maven-publish' apply plugin: 'com.jfrog.bintray' dependencies { - testCompile 'junit:junit:4.12' - testCompile 'org.apache.commons:commons-lang3:3.9' - testCompile 'org.apache.commons:commons-collections4:4.1' testCompile 'commons-codec:commons-codec:1.13' + testCompile 'org.apache.commons:commons-collections4:4.1' + testCompile 'org.apache.commons:commons-lang3:3.9' + testCompile 'junit:junit:4.12' } version='1.1.2' diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index ea300aa6..0069d291 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -55,6 +55,7 @@ public class TypeMaker { private HashMap descriptorToObjectType = new HashMap<>(1024); private HashMap internalTypeNameToObjectType = new HashMap<>(1024); private HashMap internalTypeNameToTypeTypes = new HashMap<>(1024); + private HashMap internalTypeNameMethodNameParameterCountToBoolean = new HashMap<>(1024); private HashMap internalTypeNameMethodNameDescriptorToMethodTypes = new HashMap<>(1024); private HashMap signatureToMethodTypes = new HashMap<>(1024); @@ -1550,11 +1551,23 @@ private void loadFieldsAndMethods(String internalTypeName, byte[] data) throws E String name = (String)constants[nameIndex]; String descriptor = (String)constants[descriptorIndex]; String key = internalTypeName + ':' + name + descriptor; + MethodTypes methodTypes; if (signature == null) { - internalTypeNameMethodNameDescriptorToMethodTypes.put(key, parseMethodSignature(descriptor, exceptionTypeNames)); + methodTypes = parseMethodSignature(descriptor, exceptionTypeNames); } else { - internalTypeNameMethodNameDescriptorToMethodTypes.put(key, parseMethodSignature(descriptor, signature, exceptionTypeNames)); + methodTypes = parseMethodSignature(descriptor, signature, exceptionTypeNames); + } + + internalTypeNameMethodNameDescriptorToMethodTypes.put(key, methodTypes); + + int parameterCount = (methodTypes.parameterTypes == null) ? 0 : methodTypes.parameterTypes.size(); + key = internalTypeName + ':' + name + ':' + parameterCount; + + if (internalTypeNameMethodNameParameterCountToBoolean.containsKey(key)) { + internalTypeNameMethodNameParameterCountToBoolean.put(key, Boolean.TRUE); + } else { + internalTypeNameMethodNameParameterCountToBoolean.put(key, Boolean.FALSE); } } } @@ -1763,6 +1776,52 @@ public String toString() { } } + public boolean multipleMethods(String internalTypeName, String name, int parameterCount) { + String suffixKey = ":" + name + ':' + parameterCount; + Boolean bool = multipleMethods(internalTypeName, suffixKey); + return (bool == null) ? false : bool.booleanValue(); + } + + private Boolean multipleMethods(String internalTypeName, String suffixKey) { + String key = internalTypeName + suffixKey; + Boolean bool = internalTypeNameMethodNameParameterCountToBoolean.get(key); + + if (bool == null) { + // Load methods + if (loadFieldsAndMethods(internalTypeName)) { + bool = internalTypeNameMethodNameParameterCountToBoolean.get(key); + + if (bool == null) { + TypeTypes typeTypes = makeTypeTypes(internalTypeName); + + if (typeTypes != null) { + if (typeTypes.superType != null) { + bool = multipleMethods(typeTypes.superType.getInternalName(), suffixKey); + } + + if ((bool == null) && (typeTypes.interfaces != null)) { + if (typeTypes.interfaces.isList()) { + for (Type interfaze : typeTypes.interfaces) { + bool = multipleMethods(((ObjectType)interfaze).getInternalName(), suffixKey); + if (bool != null) + break; + } + } else { + bool = multipleMethods(((ObjectType)typeTypes.interfaces.getFirst()).getInternalName(), suffixKey); + } + } + } + } + + if (bool != null) { + internalTypeNameMethodNameParameterCountToBoolean.put(key, bool); + } + } + } + + return bool; + } + public static class TypeTypes { public ObjectType thisType; public BaseTypeParameter typeParameters; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index 714ad19e..46a7591d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -144,7 +144,7 @@ public void visit(LambdaIdentifiersExpression expression) { @Override public void visit(ReturnExpressionStatement statement) { - statement.setExpression(updateExpression(returnedType, statement.getExpression())); + statement.setExpression(updateExpression(returnedType, statement.getExpression(), false)); } @Override @@ -211,7 +211,7 @@ public void visit(ExpressionVariableInitializer declaration) { nia.getArrayInitializer().accept(this); type = t; } else { - declaration.setExpression(updateExpression(type, expression)); + declaration.setExpression(updateExpression(type, expression, false)); } } @@ -220,7 +220,8 @@ public void visit(SuperConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - expression.setParameters(updateExpressions(((ClassFileSuperConstructorInvocationExpression)expression).getParameterTypes(), parameters)); + boolean force = containsNullExpression(parameters) && typeMaker.multipleMethods(expression.getObjectType().getInternalName(), "", parameters.size()); + expression.setParameters(updateExpressions(((ClassFileSuperConstructorInvocationExpression)expression).getParameterTypes(), parameters, force)); } } @@ -229,7 +230,8 @@ public void visit(ConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - expression.setParameters(updateExpressions(((ClassFileConstructorInvocationExpression)expression).getParameterTypes(), parameters)); + boolean force = containsNullExpression(parameters) && typeMaker.multipleMethods(expression.getObjectType().getInternalName(), "", parameters.size()); + expression.setParameters(updateExpressions(((ClassFileConstructorInvocationExpression)expression).getParameterTypes(), parameters, force)); } } @@ -238,21 +240,35 @@ public void visit(MethodInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; - - parameters.accept(this); - expression.setParameters(updateExpressions(mie.getParameterTypes(), parameters)); + boolean force = containsNullExpression(parameters) && typeMaker.multipleMethods(expression.getInternalTypeName(), expression.getName(), parameters.size()); + expression.setParameters(updateExpressions(((ClassFileMethodInvocationExpression)expression).getParameterTypes(), parameters, force)); } expression.getExpression().accept(this); } + protected boolean containsNullExpression(BaseExpression parameters) { + switch (parameters.size()) { + case 0: + return false; + case 1: + return parameters.getFirst().getClass() == NullExpression.class; + default: + for (Expression parameter : parameters) { + if (parameter.getClass() == NullExpression.class) { + return true; + } + } + return false; + } + } + @Override public void visit(NewExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - expression.setParameters(updateExpressions(((ClassFileNewExpression)expression).getParameterTypes(), parameters)); + expression.setParameters(updateExpressions(((ClassFileNewExpression)expression).getParameterTypes(), parameters, false)); } } @@ -277,7 +293,7 @@ public void visit(FieldReferenceExpression expression) { Type type = typeMaker.makeFromInternalTypeName(expression.getInternalTypeName()); if (type.getName() != null) { - expression.setExpression(updateExpression(type, exp)); + expression.setExpression(updateExpression(type, exp, false)); } } } @@ -299,7 +315,7 @@ public void visit(BinaryOperatorExpression expression) { } } - expression.setRightExpression(updateExpression(expression.getLeftExpression().getType(), rightExpression)); + expression.setRightExpression(updateExpression(expression.getLeftExpression().getType(), rightExpression, false)); return; } @@ -312,30 +328,38 @@ public void visit(TernaryOperatorExpression expression) { expression.getCondition().accept(this); - expression.setExpressionTrue(updateExpression(expressionType, expression.getExpressionTrue())); - expression.setExpressionFalse(updateExpression(expressionType, expression.getExpressionFalse())); + expression.setExpressionTrue(updateExpression(expressionType, expression.getExpressionTrue(), false)); + expression.setExpressionFalse(updateExpression(expressionType, expression.getExpressionFalse(), false)); } @SuppressWarnings("unchecked") - protected BaseExpression updateExpressions(BaseType types, BaseExpression expressions) { + protected BaseExpression updateExpressions(BaseType types, BaseExpression expressions, boolean force) { if (expressions != null) { if (expressions.isList()) { DefaultList t = types.getList(); DefaultList e = expressions.getList(); for (int i = e.size() - 1; i >= 0; i--) { - e.set(i, updateExpression(t.get(i), e.get(i))); + e.set(i, updateExpression(t.get(i), e.get(i), force)); } } else { - expressions = updateExpression(types.getFirst(), (Expression) expressions); + expressions = updateExpression(types.getFirst(), (Expression) expressions, force); } } return expressions; } - private Expression updateExpression(Type type, Expression expression) { - if (match(expression)) { + private Expression updateExpression(Type type, Expression expression, boolean force) { + Class expressionClass = expression.getClass(); + + if (expressionClass == NullExpression.class) { + if (force) { + searchFirstLineNumberVisitor.init(); + expression.accept(searchFirstLineNumberVisitor); + expression = new CastExpression(searchFirstLineNumberVisitor.getLineNumber(), type, expression); + } + } else { Type expressionType = expression.getType(); if (!expressionType.equals(type) && !TYPE_OBJECT.equals(type)) { @@ -364,32 +388,21 @@ private Expression updateExpression(Type type, Expression expression) { } } } - } - if (expression.getClass() == CastExpression.class) { - CastExpression ce = (CastExpression)expression; - Type ceExpressionType = ce.getExpression().getType(); + if (expression.getClass() == CastExpression.class) { + CastExpression ce = (CastExpression)expression; + Type ceExpressionType = ce.getExpression().getType(); - if (type.isObject() && ceExpressionType.isObject() && typeMaker.isAssignable(typeBounds, (ObjectType)type, (ObjectType)ceExpressionType)) { - // Remove cast expression - expression = ce.getExpression(); + if (type.isObject() && ceExpressionType.isObject() && typeMaker.isAssignable(typeBounds, (ObjectType)type, (ObjectType)ceExpressionType)) { + // Remove cast expression + expression = ce.getExpression(); + } } - } - - expression.accept(this); - - return expression; - } - - private static final boolean match(Expression expression) { - Class expressionClass = expression.getClass(); - if (expressionClass == NullExpression.class) { - // Do not add a cast before a null value - return false; + expression.accept(this); } - return true; + return expression; } private Expression addCastExpression(Type type, Expression expression) { From e9698027891e86858a4bd5cbf0a68714777570d7 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 17 Dec 2019 14:32:29 +0100 Subject: [PATCH 113/211] Fix syntax errors in decompiled sources --- .../visitor/AddCastExpressionVisitor.java | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index 46a7591d..4b4a8b11 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -220,7 +220,7 @@ public void visit(SuperConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - boolean force = containsNullExpression(parameters) && typeMaker.multipleMethods(expression.getObjectType().getInternalName(), "", parameters.size()); + boolean force = (parameters.size() > 0) && typeMaker.multipleMethods(expression.getObjectType().getInternalName(), "", parameters.size()); expression.setParameters(updateExpressions(((ClassFileSuperConstructorInvocationExpression)expression).getParameterTypes(), parameters, force)); } } @@ -230,7 +230,7 @@ public void visit(ConstructorInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - boolean force = containsNullExpression(parameters) && typeMaker.multipleMethods(expression.getObjectType().getInternalName(), "", parameters.size()); + boolean force = (parameters.size() > 0) && typeMaker.multipleMethods(expression.getObjectType().getInternalName(), "", parameters.size()); expression.setParameters(updateExpressions(((ClassFileConstructorInvocationExpression)expression).getParameterTypes(), parameters, force)); } } @@ -240,29 +240,13 @@ public void visit(MethodInvocationExpression expression) { BaseExpression parameters = expression.getParameters(); if (parameters != null) { - boolean force = containsNullExpression(parameters) && typeMaker.multipleMethods(expression.getInternalTypeName(), expression.getName(), parameters.size()); + boolean force = (parameters.size() > 0) && typeMaker.multipleMethods(expression.getInternalTypeName(), expression.getName(), parameters.size()); expression.setParameters(updateExpressions(((ClassFileMethodInvocationExpression)expression).getParameterTypes(), parameters, force)); } expression.getExpression().accept(this); } - protected boolean containsNullExpression(BaseExpression parameters) { - switch (parameters.size()) { - case 0: - return false; - case 1: - return parameters.getFirst().getClass() == NullExpression.class; - default: - for (Expression parameter : parameters) { - if (parameter.getClass() == NullExpression.class) { - return true; - } - } - return false; - } - } - @Override public void visit(NewExpression expression) { BaseExpression parameters = expression.getParameters(); From 64a317c8175ca78b8d51e2815319a531b2593ca9 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 17 Dec 2019 16:02:37 +0100 Subject: [PATCH 114/211] Fix syntax errors in decompiled sources --- .../model/localvariable/Frame.java | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index adda345a..c0b6b830 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -15,6 +15,7 @@ import org.jd.core.v1.model.javasyntax.statement.Statements; import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.LocalVariableMaker; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchUndeclaredLocalVariableVisitor; @@ -170,13 +171,6 @@ public void addChild(Frame child) { children.add(child); } - public void addNewExpression(NewExpression ne, AbstractLocalVariable lv) { - if (newExpressions == null) { - newExpressions = new HashMap<>(); - } - newExpressions.put(ne, lv); - } - public void close() { // Update lastType for 'new' expression if (newExpressions != null) { @@ -340,17 +334,6 @@ protected boolean createInlineDeclarations() { break; } } - - if (!undeclaredLocalVariables.isEmpty()) { - DefaultList sorted = new DefaultList<>(undeclaredLocalVariables); - sorted.sort(ABSTRACT_LOCAL_VARIABLE_COMPARATOR); - - for (AbstractLocalVariable lv : sorted) { - // Create start-block declarations - statements.add(0, new LocalVariableDeclarationStatement(lv.getType(), new LocalVariableDeclarator(lv.getName()))); - lv.setDeclared(true); - } - } } } @@ -610,14 +593,18 @@ protected LocalVariableDeclarators createDeclarators1(DefaultList 0) { AbstractLocalVariable lv = localVariableArray[i]; while (lv != null) { - if ((this != lv.getFrame()) && !lv.isDeclared()) { - statements.add(0, new LocalVariableDeclarationStatement(lv.getType(), new LocalVariableDeclarator(lv.getName()))); + if (!lv.isDeclared()) { + if (addIndex == -1) { + addIndex = getAddIndex(); + } + statements.add(addIndex, new LocalVariableDeclarationStatement(lv.getType(), new LocalVariableDeclarator(lv.getName()))); lv.setDeclared(true); } @@ -626,6 +613,31 @@ protected void createStartBlockDeclarations() { } } + protected int getAddIndex() { + int addIndex = 0; + + if (parent.parent == null) { + // Insert declarations after 'super' call invocation => Search index of SuperConstructorInvocationExpression. + int len = statements.size(); + + while (addIndex < len) { + Statement statement = statements.get(addIndex++); + if (statement.getClass() == ExpressionStatement.class) { + Expression expression = ((ExpressionStatement)statement).getExpression(); + if (expression.getClass() == ClassFileSuperConstructorInvocationExpression.class) { + break; + } + } + } + + if (addIndex >= len) { + addIndex = 0; + } + } + + return addIndex; + } + @SuppressWarnings("unchecked") protected void mergeDeclarations() { int size = statements.size(); From a58e6d6e37a003045ffa34be57ce0f99c5846452 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 17 Dec 2019 16:22:35 +0100 Subject: [PATCH 115/211] Fix syntax errors in decompiled sources --- .../classfiletojavasyntax/model/localvariable/Frame.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index c0b6b830..5ec878c2 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -14,6 +14,7 @@ import org.jd.core.v1.model.javasyntax.statement.Statement; import org.jd.core.v1.model.javasyntax.statement.Statements; import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; @@ -623,8 +624,8 @@ protected int getAddIndex() { while (addIndex < len) { Statement statement = statements.get(addIndex++); if (statement.getClass() == ExpressionStatement.class) { - Expression expression = ((ExpressionStatement)statement).getExpression(); - if (expression.getClass() == ClassFileSuperConstructorInvocationExpression.class) { + Class expressionClass = ((ExpressionStatement)statement).getExpression().getClass(); + if ((expressionClass == ClassFileSuperConstructorInvocationExpression.class) || (expressionClass == ClassFileConstructorInvocationExpression.class)) { break; } } From b199ffcf90d26b8413590e85ad205da5b8528db7 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 17 Dec 2019 18:01:42 +0100 Subject: [PATCH 116/211] Fix syntax errors in decompiled sources --- .../util/LocalVariableMaker.java | 31 ++----------------- .../util/StatementMaker.java | 6 ++-- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 5ca5e96c..c8ec38bb 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -333,7 +333,9 @@ protected AbstractLocalVariable searchLocalVariable(int index, int offset) { } public boolean isCompatible(AbstractLocalVariable lv, Type valueType) { - if (valueType.isObject() && (lv.getType().getDimension() == valueType.getDimension())) { + if (valueType == ObjectType.TYPE_UNDEFINED_OBJECT) { + return true; + } else if (valueType.isObject() && (lv.getType().getDimension() == valueType.getDimension())) { ObjectType valueObjectType = (ObjectType) valueType; if (lv.getType().isObject()) { @@ -389,33 +391,6 @@ public AbstractLocalVariable getLocalVariableInAssignment(Map return lv; } - public AbstractLocalVariable getLocalVariableInCastAssignment(Map typeBounds, int index, int offset, Type castType, Type valueType) { - AbstractLocalVariable lv = searchLocalVariable(index, offset); - - if (lv == null) { - // Create a new local variable - createLocalVariableVisitor.init(index, offset); - valueType.accept(createLocalVariableVisitor); - lv = createLocalVariableVisitor.getLocalVariable(); - } else if (lv.isAssignableFrom(typeBounds, castType) || isCompatible(lv, castType)) { - // Assignable, reduce type - lv.typeOnRight(typeBounds, castType); - } else if (lv.isAssignableFrom(typeBounds, valueType) || isCompatible(lv, valueType)) { - // Assignable, reduce type - lv.typeOnRight(typeBounds, valueType); - } else if (!lv.getType().isGeneric() || (ObjectType.TYPE_OBJECT != valueType)) { - // Not assignable -> Create a new local variable - createLocalVariableVisitor.init(index, offset); - valueType.accept(createLocalVariableVisitor); - lv = createLocalVariableVisitor.getLocalVariable(); - } - - lv.setToOffset(offset); - store(lv); - - return lv; - } - public AbstractLocalVariable getLocalVariableInNullAssignment(int index, int offset, Type valueType) { AbstractLocalVariable lv = searchLocalVariable(index, offset); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 99d7e27d..71dbf693 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -38,7 +38,7 @@ import java.util.*; -import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; import static org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock.*; @@ -907,10 +907,10 @@ protected TernaryOperatorExpression newTernaryOperatorExpression(int lineNumber, } else if (typeMaker.isAssignable(typeBounds, ot2, ot1)) { type = getTernaryOperatorExpressionType(ot2, ot1); } else { - type = TYPE_OBJECT; + type = TYPE_UNDEFINED_OBJECT; } } else { - type = TYPE_OBJECT; + type = TYPE_UNDEFINED_OBJECT; } return new TernaryOperatorExpression(lineNumber, type, condition, expressionTrue, expressionFalse); From df30945b75bbb17e8f6527a65878a55b747885d1 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 19 Dec 2019 12:26:08 +0100 Subject: [PATCH 117/211] Fix syntax errors in decompiled sources --- .../model/localvariable/ObjectLocalVariable.java | 2 +- .../converter/classfiletojavasyntax/util/ByteCodeParser.java | 2 ++ .../util/TypeParametersToTypeArgumentsBinder.java | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index d9177ac4..1fdba8a9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -139,7 +139,7 @@ public void typeOnRight(Map typeBounds, Type type) { @Override public void typeOnLeft(Map typeBounds, Type type) { - if (type != TYPE_UNDEFINED_OBJECT) { + if ((type != TYPE_UNDEFINED_OBJECT) && !type.equals(TYPE_OBJECT)) { if (this.type == TYPE_UNDEFINED_OBJECT) { this.type = type; fireChangeEvent(typeBounds); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index bd40d83e..844d0a3e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -891,12 +891,14 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack 0)) { + if (statements != null) { if (statements.isList()) { - Statement statement = statements.getFirst(); + // Multiple statements + if ((statements.size() > 0) && isAssertionsDisabled(statements.getFirst())) { + // Remove assert initialization statement + statements.getList().removeFirst(); + } + + if (statements.size() > 0) { + DefaultList list = statements.getList(); + Iterator fieldDeclaratorIterator = fields.iterator(); +// int lastLineNumber = 0; + + for (int i=0, len=list.size(); i 0) { + // Split 'static' block + BaseStatement newStatements; - if (cdes.getExpression().getClass() == BinaryOperatorExpression.class) { - BinaryOperatorExpression cfboe = (BinaryOperatorExpression) cdes.getExpression(); + if (i == 1) { + newStatements = list.removeFirst(); + } else { + List subList = list.subList(0, i); + newStatements = new Statements(subList); + subList.clear(); + } - if (cfboe.getLeftExpression().getClass() == FieldReferenceExpression.class) { - FieldReferenceExpression fre = (FieldReferenceExpression) cfboe.getLeftExpression(); + // Removes statements from original list + len -= newStatements.size(); + i = 0; - if ((fre.getType() == PrimitiveType.TYPE_BOOLEAN) && fre.getInternalTypeName().equals(internalTypeName) && fre.getName().equals("$assertionsDisabled")) { - // Remove assert initialization statement - statements.getList().removeFirst(); + addStaticInitializerDeclaration(sid, getFirstLineNumber(newStatements), newStatements); } + + // Remove field initialization statement + list.remove(i--); + len--; +// TODO Fix problem with local variable declarations before split static block +// lastLineNumber = 0; +// } else { +// int newLineNumber = getFirstLineNumber(statement); +// +// if ((lastLineNumber > 0) && (newLineNumber > 0) && (lastLineNumber + 3 < newLineNumber)) { +// // Split 'static' block +// BaseStatement newStatements; +// +// if (i == 1) { +// newStatements = list.removeFirst(); +// } else { +// List subList = list.subList(0, i); +// newStatements = new Statements(subList); +// subList.clear(); +// } +// +// // Removes statements from original list +// len -= newStatements.size(); +// i = 0; +// +// addStaticInitializerDeclaration(sid, newLineNumber, newStatements); +// } +// +// lastLineNumber = newLineNumber; } } } + } else { + // Single statement + if (isAssertionsDisabled(statements.getFirst())) { + // Remove assert initialization statement + statements = null; + } + if ((statements != null) && setStaticFieldInitializer(statements.getFirst(), fields.iterator())) { + // Remove field initialization statement + statements = null; + } + } + + if ((statements == null) || (statements.size() == 0)) { + deleteStaticDeclaration = Boolean.TRUE; + } else { + int firstLineNumber = getFirstLineNumber(statements); + sid.setFirstLineNumber((firstLineNumber==-1) ? 0 : firstLineNumber); + deleteStaticDeclaration = Boolean.FALSE; } + } + } - Iterator statementIterator = statements.iterator(); - Iterator fieldDeclaratorIterator = fields.iterator(); + protected boolean isAssertionsDisabled(Statement statement) { + if ((statement.getClass() == ExpressionStatement.class)) { + ExpressionStatement cdes = (ExpressionStatement) statement; - while (statementIterator.hasNext()) { - Statement statement = statementIterator.next(); + if (cdes.getExpression().getClass() == BinaryOperatorExpression.class) { + BinaryOperatorExpression cfboe = (BinaryOperatorExpression) cdes.getExpression(); - if (statement.getClass() != ExpressionStatement.class) { - break; + if (cfboe.getLeftExpression().getClass() == FieldReferenceExpression.class) { + FieldReferenceExpression fre = (FieldReferenceExpression) cfboe.getLeftExpression(); + + if ((fre.getType() == PrimitiveType.TYPE_BOOLEAN) && fre.getInternalTypeName().equals(internalTypeName) && fre.getName().equals("$assertionsDisabled")) { + return true; + } } + } + } - ExpressionStatement cdes = (ExpressionStatement) statement; + return false; + } - if (cdes.getExpression().getClass() != BinaryOperatorExpression.class) { - break; - } + protected boolean setStaticFieldInitializer(Statement statement, Iterator fieldDeclaratorIterator) { + if (statement.getClass() == ExpressionStatement.class) { + ExpressionStatement cdes = (ExpressionStatement) statement; + if (cdes.getExpression().getClass() == BinaryOperatorExpression.class) { BinaryOperatorExpression cfboe = (BinaryOperatorExpression) cdes.getExpression(); - if (cfboe.getLeftExpression().getClass() != FieldReferenceExpression.class) { - break; - } + if (cfboe.getLeftExpression().getClass() == FieldReferenceExpression.class) { + FieldReferenceExpression fre = (FieldReferenceExpression) cfboe.getLeftExpression(); - FieldReferenceExpression fre = (FieldReferenceExpression) cfboe.getLeftExpression(); + if (fre.getInternalTypeName().equals(internalTypeName)) { + while (fieldDeclaratorIterator.hasNext()) { + FieldDeclarator fdr = fieldDeclaratorIterator.next(); + FieldDeclaration fdn = fdr.getFieldDeclaration(); - if (!fre.getInternalTypeName().equals(internalTypeName)) { - break; - } + if (((fdn.getFlags() & Declaration.FLAG_STATIC) != 0) && fdr.getName().equals(fre.getName()) && fdn.getType().getDescriptor().equals(fre.getDescriptor())) { + Expression expression = cfboe.getRightExpression(); - FieldDeclarator fieldDeclarator = null; + searchLocalVariableReferenceVisitor.init(-1); + expression.accept(searchLocalVariableReferenceVisitor); - while (fieldDeclaratorIterator.hasNext()) { - FieldDeclarator fdr = fieldDeclaratorIterator.next(); - FieldDeclaration fdn = fdr.getFieldDeclaration(); + if (searchLocalVariableReferenceVisitor.containsReference()) { + return false; + } - if (((fdn.getFlags() & Declaration.FLAG_STATIC) != 0) && fdr.getName().equals(fre.getName()) && fdn.getType().getDescriptor().equals(fre.getDescriptor())) { - fieldDeclarator = fdr; - break; - } - } - - if (fieldDeclarator == null) { - break; - } else { - Expression expression = cfboe.getRightExpression(); + fdr.setVariableInitializer(new ExpressionVariableInitializer(expression)); + ((ClassFileFieldDeclaration)fdr.getFieldDeclaration()).setFirstLineNumber(expression.getLineNumber()); - fieldDeclarator.setVariableInitializer(new ExpressionVariableInitializer(expression)); - ((ClassFileFieldDeclaration)fieldDeclarator.getFieldDeclaration()).setFirstLineNumber(expression.getLineNumber()); - statementIterator.remove(); + return true; + } + } + } } } + } - if (statements.size() == 0) { - staticDeclaration.setStatements(null); - staticDeclaration.setFirstLineNumber(0); - } else { - searchFirstLineNumberVisitor.init(); - staticDeclaration.getStatements().accept(searchFirstLineNumberVisitor); - int firstLineNumber = searchFirstLineNumberVisitor.getLineNumber(); + return false; + } - staticDeclaration.setFirstLineNumber((firstLineNumber==-1) ? 0 : firstLineNumber); - } - } + protected int getFirstLineNumber(BaseStatement baseStatement) { + searchFirstLineNumberVisitor.init(); + baseStatement.accept(searchFirstLineNumberVisitor); + return searchFirstLineNumberVisitor.getLineNumber(); } - @Override - public void visit(FieldDeclarator declaration) { - fields.add(declaration); + protected void addStaticInitializerDeclaration(ClassFileStaticInitializerDeclaration sid, int lineNumber, BaseStatement statements) { + methods.add(new ClassFileStaticInitializerDeclaration( + sid.getBodyDeclaration(), sid.getClassFile(), sid.getMethod(), sid.getBindings(), + sid.getTypeBounds(), lineNumber, statements)); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableReferenceVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableReferenceVisitor.java index 6b415a94..49ab61d5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableReferenceVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableReferenceVisitor.java @@ -16,8 +16,8 @@ public class SearchLocalVariableReferenceVisitor extends AbstractJavaSyntaxVisit protected int index; protected boolean found; - public SearchLocalVariableReferenceVisitor(AbstractLocalVariable alv) { - this.index = alv.getIndex(); + public void init(int index) { + this.index = index; this.found = false; } @@ -27,7 +27,11 @@ public boolean containsReference() { @Override public void visit(LocalVariableReferenceExpression expression) { - ClassFileLocalVariableReferenceExpression referenceExpression = (ClassFileLocalVariableReferenceExpression)expression; - found |= referenceExpression.getLocalVariable().getIndex() == index; + if (index < 0) { + found = true; + } else { + ClassFileLocalVariableReferenceExpression referenceExpression = (ClassFileLocalVariableReferenceExpression) expression; + found |= referenceExpression.getLocalVariable().getIndex() == index; + } } } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 2c3964ff..e9e65fb4 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -1206,7 +1206,6 @@ public void visit(StaticInitializerDeclaration declaration) { tokens = new Tokens(); tokens.add(STATIC); - tokens.add(TextToken.SPACE); fragments.addTokensFragment(tokens); StartBodyFragment start = JavaFragmentFactory.addStartMethodBody(fragments); From bc4a4e845f40ab4d1af057a813d2d629eea30c11 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 23 Dec 2019 11:42:34 +0100 Subject: [PATCH 119/211] Fix error in generic type decompilation --- .../BindTypeArgumentsToTypeArgumentsVisitor.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java index 46056980..2c698140 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeArgumentsToTypeArgumentsVisitor.java @@ -111,9 +111,7 @@ public void visit(ObjectType type) { } else { typeArguments.accept(this); - if (typeArguments == WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT) { - result = WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; - } else if (typeArguments == result) { + if (typeArguments == result) { result = type; } else if (result != null) { result = type.createType(result); @@ -133,9 +131,7 @@ public void visit(InnerObjectType type) { } else { typeArguments.accept(this); - if (typeArguments == WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT) { - result = WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; - } else if (typeArguments == result) { + if (typeArguments == result) { result = type; } else if (result != null) { result = type.createType(result); @@ -149,11 +145,7 @@ public void visit(InnerObjectType type) { typeArguments = result; } - if (typeArguments == WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT) { - result = WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; - } else { - result = new InnerObjectType(type.getInternalName(), type.getQualifiedName(), type.getName(), typeArguments, type.getDimension(), outerObjectType); - } + result = new InnerObjectType(type.getInternalName(), type.getQualifiedName(), type.getName(), typeArguments, type.getDimension(), outerObjectType); } } From 66ea8c7c8b2e58dc493ddbef127655d1ce2e128c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 25 Dec 2019 12:42:49 +0100 Subject: [PATCH 120/211] Fix syntax errors in decompiled sources --- .../javasyntax/AbstractJavaSyntaxVisitor.java | 25 ++--- .../AbstractNopExpressionVisitor.java | 1 - .../expression/ExpressionVisitor.java | 1 - .../MethodInvocationExpression.java | 10 ++ .../javasyntax/expression/NewExpression.java | 19 +--- .../expression/NewInnerExpression.java | 39 ------- .../javasyntax/type/TypeParameterVisitor.java | 6 +- .../ClassFileMethodInvocationExpression.java | 2 +- .../expression/ClassFileNewExpression.java | 4 +- .../processor/ConvertClassFileProcessor.java | 10 +- .../classfiletojavasyntax/util/TypeMaker.java | 44 ++++---- .../TypeParametersToTypeArgumentsBinder.java | 105 +++++++++++------- .../AbstractUpdateExpressionVisitor.java | 7 -- ...tersToNonWildcardTypeArgumentsVisitor.java | 76 +++++++++++++ ...itor.java => BindTypesToTypesVisitor.java} | 2 +- ...DeclaredSyntheticLocalVariableVisitor.java | 1 - ...ulateBindingsWithTypeParameterVisitor.java | 16 +-- .../visitor/SearchFirstLineNumberVisitor.java | 1 - .../visitor/ExpressionVisitor.java | 24 ++-- .../visitor/SearchImportsVisitor.java | 14 --- .../visitor/SingleLineStatementVisitor.java | 5 - .../visitor/TypeVisitor.java | 9 +- ...eParametersToTypeArgumentsVisitorTest.java | 6 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 9 +- .../jd/core/v1/JarFileToJavaSourceTest.java | 24 ++-- .../core/v1/JavaSyntaxToJavaSourceTest.java | 1 + 26 files changed, 242 insertions(+), 219 deletions(-) delete mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToNonWildcardTypeArgumentsVisitor.java rename src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/{BindTypeParametersToTypeArgumentsVisitor.java => BindTypesToTypesVisitor.java} (98%) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java index df7c5e7a..7b770596 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java @@ -297,8 +297,9 @@ public void visit(LongConstantExpression expression) { @Override public void visit(MethodInvocationExpression expression) { - safeAccept(expression.getParameters()); expression.getExpression().accept(this); + safeAccept(expression.getNonWildcardTypeArguments()); + safeAccept(expression.getParameters()); } @Override @@ -319,7 +320,6 @@ public void visit(NewExpression expression) { BaseType type = expression.getType(); type.accept(this); - safeAccept(expression.getNonWildcardTypeArguments()); safeAccept(expression.getParameters()); // safeAccept(expression.getBodyDeclaration()); } @@ -332,17 +332,6 @@ public void visit(NewInitializedArray expression) { safeAccept(expression.getArrayInitializer()); } - @Override - public void visit(NewInnerExpression expression) { - BaseType type = expression.getType(); - - type.accept(this); - expression.getExpression().accept(this); - safeAccept(expression.getNonWildcardTypeArguments()); - safeAccept(expression.getParameters()); - //safeAccept(expression.getBodyDeclaration()); - } - @Override public void visit(NullExpression expression) { BaseType type = expression.getType(); @@ -627,16 +616,16 @@ public void visit(WhileStatement statement) { } @Override - public void visit(TypeParameter type) {} + public void visit(TypeParameter parameter) {} @Override - public void visit(TypeParameterWithTypeBounds type) { - type.getTypeBounds().accept(this); + public void visit(TypeParameterWithTypeBounds parameter) { + parameter.getTypeBounds().accept(this); } @Override - public void visit(TypeParameters types) { - Iterator iterator = types.iterator(); + public void visit(TypeParameters parameters) { + Iterator iterator = parameters.iterator(); while (iterator.hasNext()) iterator.next().accept(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java index 903abc42..a31530b9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java @@ -32,7 +32,6 @@ public abstract class AbstractNopExpressionVisitor implements ExpressionVisitor @Override public void visit(NewArray expression) {} @Override public void visit(NewExpression expression) {} @Override public void visit(NewInitializedArray expression) {} - @Override public void visit(NewInnerExpression expression) {} @Override public void visit(NullExpression expression) {} @Override public void visit(ObjectTypeReferenceExpression expression) {} @Override public void visit(ParenthesesExpression expression) {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java index af4ec550..88a60a82 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java @@ -32,7 +32,6 @@ public interface ExpressionVisitor { void visit(NewArray expression); void visit(NewExpression expression); void visit(NewInitializedArray expression); - void visit(NewInnerExpression expression); void visit(NullExpression expression); void visit(ObjectTypeReferenceExpression expression); void visit(ParenthesesExpression expression); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java index adb37e85..e425a672 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java @@ -7,9 +7,11 @@ package org.jd.core.v1.model.javasyntax.expression; +import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; import org.jd.core.v1.model.javasyntax.type.Type; public class MethodInvocationExpression extends MethodReferenceExpression { + protected BaseTypeArgument nonWildcardTypeArguments; protected BaseExpression parameters; public MethodInvocationExpression(Type type, Expression expression, String internalTypeName, String name, String descriptor) { @@ -30,6 +32,14 @@ public MethodInvocationExpression(int lineNumber, Type type, Expression expressi this.parameters = parameters; } + public BaseTypeArgument getNonWildcardTypeArguments() { + return nonWildcardTypeArguments; + } + + public void setNonWildcardTypeArguments(BaseTypeArgument nonWildcardTypeArguments) { + this.nonWildcardTypeArguments = nonWildcardTypeArguments; + } + public BaseExpression getParameters() { return parameters; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java index 54ce1823..fdb613ac 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java @@ -8,41 +8,28 @@ package org.jd.core.v1.model.javasyntax.expression; import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; -import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; public class NewExpression extends AbstractLineNumberExpression { - protected BaseTypeArgument nonWildcardTypeArguments; protected ObjectType type; protected String descriptor; protected BaseExpression parameters; protected BodyDeclaration bodyDeclaration; - public NewExpression(int lineNumber, ObjectType type) { + public NewExpression(int lineNumber, ObjectType type, String descriptor) { super(lineNumber); this.type = type; + this.descriptor = descriptor; } - public NewExpression(int lineNumber, ObjectType type, BodyDeclaration bodyDeclaration) { - super(lineNumber); - this.type = type; - this.bodyDeclaration = bodyDeclaration; - } - - public NewExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, String descriptor, BaseExpression parameters, BodyDeclaration bodyDeclaration) { + public NewExpression(int lineNumber, ObjectType type, String descriptor, BodyDeclaration bodyDeclaration) { super(lineNumber); - this.nonWildcardTypeArguments = nonWildcardTypeArguments; this.type = type; this.descriptor = descriptor; - this.parameters = parameters; this.bodyDeclaration = bodyDeclaration; } - public BaseTypeArgument getNonWildcardTypeArguments() { - return nonWildcardTypeArguments; - } - public ObjectType getObjectType() { return type; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java deleted file mode 100644 index 53dcb7a6..00000000 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInnerExpression.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2008-2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.model.javasyntax.expression; - -import org.jd.core.v1.model.javasyntax.declaration.BodyDeclaration; -import org.jd.core.v1.model.javasyntax.type.BaseTypeArgument; -import org.jd.core.v1.model.javasyntax.type.ObjectType; - -public class NewInnerExpression extends NewExpression { - protected Expression expression; - - public NewInnerExpression(int lineNumber, BaseTypeArgument nonWildcardTypeArguments, ObjectType type, String descriptor, BaseExpression parameters, BodyDeclaration bodyDeclaration, Expression expression) { - super(lineNumber, nonWildcardTypeArguments, type, descriptor, parameters, bodyDeclaration); - this.expression = expression; - } - - public Expression getExpression() { - return expression; - } - - public void setExpression(Expression expression) { - this.expression = expression; - } - - @Override - public int getPriority() { - return 3; - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } -} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java index ada09dfe..ac640fa5 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/type/TypeParameterVisitor.java @@ -8,7 +8,7 @@ package org.jd.core.v1.model.javasyntax.type; public interface TypeParameterVisitor { - void visit(TypeParameter type); - void visit(TypeParameterWithTypeBounds type); - void visit(TypeParameters types); + void visit(TypeParameter parameter); + void visit(TypeParameterWithTypeBounds parameter); + void visit(TypeParameters parameters); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java index 302ec51e..fe244790 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileMethodInvocationExpression.java @@ -16,9 +16,9 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeParametersToTypeArgumentsBinder; public class ClassFileMethodInvocationExpression extends MethodInvocationExpression { + protected TypeParametersToTypeArgumentsBinder binder; protected BaseTypeParameter typeParameters; protected BaseType parameterTypes; - protected TypeParametersToTypeArgumentsBinder binder; public ClassFileMethodInvocationExpression( TypeParametersToTypeArgumentsBinder binder, diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java index 1e2df12e..810fe179 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileNewExpression.java @@ -17,11 +17,11 @@ public class ClassFileNewExpression extends NewExpression { protected BaseType parameterTypes; public ClassFileNewExpression(int lineNumber, ObjectType type) { - super(lineNumber, type); + super(lineNumber, type, null); } public ClassFileNewExpression(int lineNumber, ObjectType type, BodyDeclaration bodyDeclaration) { - super(lineNumber, type, bodyDeclaration); + super(lineNumber, type, null, bodyDeclaration); } public BaseType getParameterTypes() { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java index 389a0de8..84ac92f1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/processor/ConvertClassFileProcessor.java @@ -43,13 +43,13 @@ public class ConvertClassFileProcessor implements Processor { protected PopulateBindingsWithTypeParameterVisitor populateBindingsWithTypeParameterVisitor = new PopulateBindingsWithTypeParameterVisitor() { @Override - public void visit(TypeParameter type) { - bindings.put(type.getIdentifier(), new GenericType(type.getIdentifier())); + public void visit(TypeParameter parameter) { + bindings.put(parameter.getIdentifier(), new GenericType(parameter.getIdentifier())); } @Override - public void visit(TypeParameterWithTypeBounds type) { - bindings.put(type.getIdentifier(), new GenericType(type.getIdentifier())); - typeBounds.put(type.getIdentifier(), type.getTypeBounds()); + public void visit(TypeParameterWithTypeBounds parameter) { + bindings.put(parameter.getIdentifier(), new GenericType(parameter.getIdentifier())); + typeBounds.put(parameter.getIdentifier(), parameter.getTypeBounds()); } }; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java index 0069d291..98b9aa06 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeMaker.java @@ -14,7 +14,7 @@ import org.jd.core.v1.model.classfile.Method; import org.jd.core.v1.model.classfile.attribute.*; import org.jd.core.v1.model.javasyntax.type.*; -import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.BindTypeParametersToTypeArgumentsVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.BindTypesToTypesVisitor; import org.jd.core.v1.service.deserializer.classfile.ClassFileFormatException; import org.jd.core.v1.service.deserializer.classfile.ClassFileReader; @@ -940,7 +940,7 @@ private ObjectType searchSuperParameterizedType(long superHashCode, String super } } } else { - BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); + BindTypesToTypesVisitor bindTypesToTypesVisitor = new BindTypesToTypesVisitor(); HashMap bindings = new HashMap<>(); if (rightTypeTypes.typeParameters.isList() && objectType.getTypeArguments().isTypeArgumentList()) { @@ -954,12 +954,12 @@ private ObjectType searchSuperParameterizedType(long superHashCode, String super bindings.put(rightTypeTypes.typeParameters.getFirst().getIdentifier(), objectType.getTypeArguments().getTypeArgumentFirst()); } - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + bindTypesToTypesVisitor.setBindings(bindings); if (rightTypeTypes.superType != null) { - bindTypeParametersToTypeArgumentsVisitor.init(); - rightTypeTypes.superType.accept(bindTypeParametersToTypeArgumentsVisitor); - ObjectType ot = (ObjectType) bindTypeParametersToTypeArgumentsVisitor.getType(); + bindTypesToTypesVisitor.init(); + rightTypeTypes.superType.accept(bindTypesToTypesVisitor); + ObjectType ot = (ObjectType) bindTypesToTypesVisitor.getType(); ot = searchSuperParameterizedType(superHashCode, superInternalTypeName, ot); if (ot != null) { @@ -969,9 +969,9 @@ private ObjectType searchSuperParameterizedType(long superHashCode, String super } if (rightTypeTypes.interfaces != null) { for (Type interfaze : rightTypeTypes.interfaces) { - bindTypeParametersToTypeArgumentsVisitor.init(); - interfaze.accept(bindTypeParametersToTypeArgumentsVisitor); - ObjectType ot = (ObjectType) bindTypeParametersToTypeArgumentsVisitor.getType(); + bindTypesToTypesVisitor.init(); + interfaze.accept(bindTypesToTypesVisitor); + ObjectType ot = (ObjectType) bindTypesToTypesVisitor.getType(); ot = searchSuperParameterizedType(superHashCode, superInternalTypeName, ot); if (ot != null) { @@ -1212,7 +1212,7 @@ private Type loadFieldType(ObjectType objectType, String fieldName, String descr TypeTypes typeTypes = makeTypeTypes(internalTypeName); if (typeTypes.typeParameters != null) { - BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); + BindTypesToTypesVisitor bindTypesToTypesVisitor = new BindTypesToTypesVisitor(); HashMap bindings = new HashMap<>(); if (typeTypes.typeParameters.isList() && typeArguments.isTypeArgumentList()) { @@ -1226,11 +1226,11 @@ private Type loadFieldType(ObjectType objectType, String fieldName, String descr bindings.put(typeTypes.typeParameters.getFirst().getIdentifier(), typeArguments.getTypeArgumentFirst()); } - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + bindTypesToTypesVisitor.setBindings(bindings); - bindTypeParametersToTypeArgumentsVisitor.init(); - type.accept(bindTypeParametersToTypeArgumentsVisitor); - type = (Type) bindTypeParametersToTypeArgumentsVisitor.getType(); + bindTypesToTypesVisitor.init(); + type.accept(bindTypesToTypesVisitor); + type = (Type) bindTypesToTypesVisitor.getType(); } } @@ -1301,7 +1301,7 @@ private MethodTypes loadMethodTypes(ObjectType objectType, String methodName, St TypeTypes typeTypes = makeTypeTypes(internalTypeName); if ((typeTypes != null) && (typeTypes.typeParameters != null)) { - BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); + BindTypesToTypesVisitor bindTypesToTypesVisitor = new BindTypesToTypesVisitor(); HashMap bindings = new HashMap<>(); MethodTypes newMethodTypes = new MethodTypes(); @@ -1316,14 +1316,14 @@ private MethodTypes loadMethodTypes(ObjectType objectType, String methodName, St bindings.put(typeTypes.typeParameters.getFirst().getIdentifier(), typeArguments.getTypeArgumentFirst()); } - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); + bindTypesToTypesVisitor.setBindings(bindings); if (methodTypes.parameterTypes == null) { newMethodTypes.parameterTypes = null; } else { - bindTypeParametersToTypeArgumentsVisitor.init(); - methodTypes.parameterTypes.accept(bindTypeParametersToTypeArgumentsVisitor); - BaseType baseType = bindTypeParametersToTypeArgumentsVisitor.getType(); + bindTypesToTypesVisitor.init(); + methodTypes.parameterTypes.accept(bindTypesToTypesVisitor); + BaseType baseType = bindTypesToTypesVisitor.getType(); if (baseType.isList() && (baseType.getClass() == Types.class)) { baseType = new UnmodifiableTypes(baseType.getList()); @@ -1332,9 +1332,9 @@ private MethodTypes loadMethodTypes(ObjectType objectType, String methodName, St newMethodTypes.parameterTypes = baseType; } - bindTypeParametersToTypeArgumentsVisitor.init(); - methodTypes.returnedType.accept(bindTypeParametersToTypeArgumentsVisitor); - newMethodTypes.returnedType = (Type)bindTypeParametersToTypeArgumentsVisitor.getType(); + bindTypesToTypesVisitor.init(); + methodTypes.returnedType.accept(bindTypesToTypesVisitor); + newMethodTypes.returnedType = (Type)bindTypesToTypesVisitor.getType(); newMethodTypes.typeParameters = null; newMethodTypes.exceptionTypes = methodTypes.exceptionTypes; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 287bad9c..32fa0125 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -9,7 +9,6 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.type.*; -import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileConstructorOrMethodDeclaration; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; @@ -22,11 +21,14 @@ import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; public class TypeParametersToTypeArgumentsBinder { + protected static final RemoveNonWildcardTypeArgumentsVisitor REMOVE_NON_WILDCARD_TYPE_ARGUMENTS_VISITOR = new RemoveNonWildcardTypeArgumentsVisitor(); + protected PopulateBindingsWithTypeParameterVisitor populateBindingsWithTypeParameterVisitor = new PopulateBindingsWithTypeParameterVisitor(); - protected BindTypeParametersToTypeArgumentsVisitor bindTypeParametersToTypeArgumentsVisitor = new BindTypeParametersToTypeArgumentsVisitor(); + protected BindTypesToTypesVisitor bindTypesToTypesVisitor = new BindTypesToTypesVisitor(); protected SearchInTypeArgumentVisitor searchInTypeArgumentVisitor = new SearchInTypeArgumentVisitor(); protected TypeArgumentToTypeVisitor typeArgumentToTypeVisitor = new TypeArgumentToTypeVisitor(); protected BaseTypeToTypeArgumentVisitor baseTypeToTypeArgumentVisitor = new BaseTypeToTypeArgumentVisitor(); + protected BindTypeParametersToNonWildcardTypeArgumentsVisitor bindTypeParametersToNonWildcardTypeArgumentsVisitor = new BindTypeParametersToNonWildcardTypeArgumentsVisitor(); protected BindVisitor bindVisitor = new BindVisitor(); protected TypeMaker typeMaker; @@ -52,8 +54,8 @@ public ClassFileConstructorInvocationExpression newConstructorInvocationExpressi BaseType parameterTypes = clone(methodTypes.parameterTypes); Map bindings = createBindings(null, null, null, methodTypes.typeParameters, TYPE_OBJECT, null, parameterTypes, parameters); - parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes); - bindParameterTypesWithArgumentTypes(parameterTypes, parameters); + parameterTypes = bind(bindings, parameterTypes); + bindParameters(parameterTypes, parameters); return new ClassFileConstructorInvocationExpression(lineNumber, objectType, descriptor, parameterTypes, parameters); } @@ -78,8 +80,8 @@ public ClassFileSuperConstructorInvocationExpression newSuperConstructorInvocati } } - parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes); - bindParameterTypesWithArgumentTypes(parameterTypes, parameters); + parameterTypes = bind(bindings, parameterTypes); + bindParameters(parameterTypes, parameters); return new ClassFileSuperConstructorInvocationExpression(lineNumber, objectType, descriptor, parameterTypes, parameters); } @@ -117,7 +119,7 @@ public FieldReferenceExpression newFieldReferenceExpression( bindings = createBindings(expression, typeParameters, typeArguments, null, TYPE_OBJECT, null, null, null); } - type = (Type)bindParameterTypesWithArgumentTypes(bindings, type); + type = (Type) bind(bindings, type); } } } @@ -133,6 +135,7 @@ public void updateNewExpression(ClassFileNewExpression ne, String descriptor, Ty public void bindParameterTypesWithArgumentTypes(Type type, Expression expression) { bindVisitor.init(type); expression.accept(bindVisitor); + expression.accept(REMOVE_NON_WILDCARD_TYPE_ARGUMENTS_VISITOR); } protected Type checkTypeArguments(Type type, AbstractLocalVariable localVariable) { @@ -156,7 +159,7 @@ protected Type checkTypeArguments(Type type, AbstractLocalVariable localVariable return type; } - protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileMethodInvocationExpression mie) { + protected void bind(Type type, ClassFileMethodInvocationExpression mie) { BaseType parameterTypes = mie.getParameterTypes(); BaseExpression parameters = mie.getParameters(); Expression expression = mie.getExpression(); @@ -195,14 +198,21 @@ protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileMethodInv } Map bindings = createBindings(expression, typeParameters, typeArguments, methodTypeParameters, type, t, parameterTypes, parameters); + boolean bindingsContainsNull = bindings.containsValue(null); + + mie.setParameterTypes(parameterTypes = bind(bindings, parameterTypes)); + mie.setType((Type) bind(bindings, mie.getType())); - mie.setParameterTypes(parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes)); - mie.setType((Type) bindParameterTypesWithArgumentTypes(bindings, mie.getType())); + if ((methodTypeParameters != null) && !bindingsContainsNull) { + bindTypeParametersToNonWildcardTypeArgumentsVisitor.init(bindings); + methodTypeParameters.accept(bindTypeParametersToNonWildcardTypeArgumentsVisitor); + mie.setNonWildcardTypeArguments(bindTypeParametersToNonWildcardTypeArgumentsVisitor.getTypeArgument()); + } if (expressionType.isObject()) { ObjectType expressionObjectType = (ObjectType) expressionType; - if (bindings.containsValue(null)) { + if (bindingsContainsNull) { expressionType = expressionObjectType.createType(null); } else { boolean statik = (expression.getClass() == ObjectTypeReferenceExpression.class); @@ -223,11 +233,13 @@ protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileMethodInv } } - bindParameterTypesWithArgumentTypes(expressionType, expression); - bindParameterTypesWithArgumentTypes(parameterTypes, parameters); + bindVisitor.init(expressionType); + expression.accept(bindVisitor); + + bindParameters(parameterTypes, parameters); } - protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileNewExpression ne) { + protected void bind(Type type, ClassFileNewExpression ne) { BaseType parameterTypes = ne.getParameterTypes(); BaseExpression parameters = ne.getParameters(); ObjectType neObjectType = ne.getObjectType(); @@ -260,7 +272,7 @@ protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileNewExpres Map bindings = createBindings(null, typeParameters, typeArguments, null, type, t, parameterTypes, parameters); - ne.setParameterTypes(parameterTypes = bindParameterTypesWithArgumentTypes(bindings, parameterTypes)); + ne.setParameterTypes(parameterTypes = bind(bindings, parameterTypes)); // Replace wildcards for (Map.Entry entry : bindings.entrySet()) { @@ -269,24 +281,30 @@ protected void bindParameterTypesWithArgumentTypes(Type type, ClassFileNewExpres entry.setValue(typeArgumentToTypeVisitor.getType()); } - ne.setType((ObjectType) bindParameterTypesWithArgumentTypes(bindings, neObjectType)); + ne.setType((ObjectType) bind(bindings, neObjectType)); } } - bindParameterTypesWithArgumentTypes(parameterTypes, parameters); + bindParameters(parameterTypes, parameters); } - protected void bindParameterTypesWithArgumentTypes(BaseType types, BaseExpression expressions) { - if (types != null) { - if (types.isList() && expressions.isList()) { - Iterator parameterTypesIterator = types.iterator(); - Iterator parametersIterator = expressions.iterator(); + protected void bindParameters(BaseType parameterTypes, BaseExpression parameters) { + if (parameterTypes != null) { + if (parameterTypes.isList() && parameters.isList()) { + Iterator parameterTypesIterator = parameterTypes.iterator(); + Iterator parametersIterator = parameters.iterator(); while (parametersIterator.hasNext()) { - bindParameterTypesWithArgumentTypes(parameterTypesIterator.next(), parametersIterator.next()); + Expression parameter = parametersIterator.next(); + bindVisitor.init(parameterTypesIterator.next()); + parameter.accept(bindVisitor); + parameter.accept(REMOVE_NON_WILDCARD_TYPE_ARGUMENTS_VISITOR); } } else { - bindParameterTypesWithArgumentTypes(types.getFirst(), expressions.getFirst()); + Expression parameter = parameters.getFirst(); + bindVisitor.init(parameterTypes.getFirst()); + parameter.accept(bindVisitor); + parameter.accept(REMOVE_NON_WILDCARD_TYPE_ARGUMENTS_VISITOR); } } } @@ -369,10 +387,10 @@ protected Map createBindings( if (baseType == null) { entry.setValue(WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT); } else { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); - bindTypeParametersToTypeArgumentsVisitor.init(); - baseType.accept(bindTypeParametersToTypeArgumentsVisitor); - baseType = bindTypeParametersToTypeArgumentsVisitor.getType(); + bindTypesToTypesVisitor.setBindings(bindings); + bindTypesToTypesVisitor.init(); + baseType.accept(bindTypesToTypesVisitor); + baseType = bindTypesToTypesVisitor.getType(); baseTypeToTypeArgumentVisitor.init(); baseType.accept(baseTypeToTypeArgumentVisitor); @@ -414,12 +432,12 @@ protected void populateBindingsWithTypeArgument(Map bindin } } - protected BaseType bindParameterTypesWithArgumentTypes(Map bindings, BaseType parameterTypes) { + protected BaseType bind(Map bindings, BaseType parameterTypes) { if ((parameterTypes != null) && !bindings.isEmpty()) { - bindTypeParametersToTypeArgumentsVisitor.setBindings(bindings); - bindTypeParametersToTypeArgumentsVisitor.init(); - parameterTypes.accept(bindTypeParametersToTypeArgumentsVisitor); - parameterTypes = bindTypeParametersToTypeArgumentsVisitor.getType(); + bindTypesToTypesVisitor.setBindings(bindings); + bindTypesToTypesVisitor.init(); + parameterTypes.accept(bindTypesToTypesVisitor); + parameterTypes = bindTypesToTypesVisitor.getType(); } return parameterTypes; @@ -504,7 +522,7 @@ public void init(Type type) { @Override public void visit(MethodInvocationExpression expression) { ClassFileMethodInvocationExpression mie = (ClassFileMethodInvocationExpression)expression; - bindParameterTypesWithArgumentTypes(type, mie); + bind(type, mie); } @Override @@ -518,7 +536,7 @@ public void visit(LocalVariableReferenceExpression expression) { @Override public void visit(NewExpression expression) { ClassFileNewExpression ne = (ClassFileNewExpression)expression; - bindParameterTypesWithArgumentTypes(type, ne); + bind(type, ne); } @Override @@ -560,16 +578,25 @@ public void visit(TernaryOperatorExpression expression) { Type t = type; expression.setType(t); - bindParameterTypesWithArgumentTypes(t, expression.getExpressionTrue()); - bindParameterTypesWithArgumentTypes(t, expression.getExpressionFalse()); + expression.getExpressionTrue().accept(this); + type = t; + expression.getExpressionFalse().accept(this); } @Override public void visit(BinaryOperatorExpression expression) { Type t = type; - bindParameterTypesWithArgumentTypes(t, expression.getLeftExpression()); - bindParameterTypesWithArgumentTypes(t, expression.getRightExpression()); + expression.getLeftExpression().accept(this); + type = t; + expression.getRightExpression().accept(this); + } + } + + protected static class RemoveNonWildcardTypeArgumentsVisitor extends AbstractNopExpressionVisitor { + @Override + public void visit(MethodInvocationExpression expression) { + expression.setNonWildcardTypeArguments(null); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java index b68c695a..efc4335e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java @@ -198,13 +198,6 @@ public void visit(NewExpression expression) { @Override public void visit(NewInitializedArray expression) {} - @Override - public void visit(NewInnerExpression expression) { - expression.setExpression(updateExpression(expression.getExpression())); - expression.getExpression().accept(this); - visit((NewExpression)expression); - } - @Override public void visit(ParenthesesExpression expression) { expression.setExpression(updateExpression(expression.getExpression())); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToNonWildcardTypeArgumentsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToNonWildcardTypeArgumentsVisitor.java new file mode 100644 index 00000000..f9cd661e --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToNonWildcardTypeArgumentsVisitor.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import java.util.Map; + +public class BindTypeParametersToNonWildcardTypeArgumentsVisitor implements TypeParameterVisitor, TypeArgumentVisitor { + protected Map bindings; + protected BaseTypeArgument result; + + public void init(Map bindings) { + this.bindings = bindings; + this.result = null; + } + + public BaseTypeArgument getTypeArgument() { + return result; + } + + // --- TypeParameterVisitor --- // + @Override + public void visit(TypeParameter parameter) { + result = bindings.get(parameter.getIdentifier()); + + if (result != null) { + result.accept(this); + } + } + + @Override + public void visit(TypeParameterWithTypeBounds parameter) { + result = bindings.get(parameter.getIdentifier()); + + if (result != null) { + result.accept(this); + } + } + + @Override + public void visit(TypeParameters parameters) { + int size = parameters.size(); + TypeArguments arguments = new TypeArguments(size); + + for (TypeParameter parameter : parameters) { + parameter.accept(this); + + if (result == null) { + return; + } + + arguments.add((TypeArgument)result); + } + + result = arguments; + } + + // --- TypeArgumentVisitor --- // + @Override public void visit(WildcardExtendsTypeArgument argument) { result = argument.getType(); } + @Override public void visit(WildcardSuperTypeArgument argument) { result = argument.getType(); } + + @Override public void visit(DiamondTypeArgument argument) { result = null; } + @Override public void visit(WildcardTypeArgument argument) { result = null; } + + @Override public void visit(TypeArguments arguments) {} + @Override public void visit(PrimitiveType type) {} + @Override public void visit(ObjectType type) {} + @Override public void visit(InnerObjectType type) {} + @Override public void visit(GenericType type) {} +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypesToTypesVisitor.java similarity index 98% rename from src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java rename to src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypesToTypesVisitor.java index 45697820..a6a13b98 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypeParametersToTypeArgumentsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BindTypesToTypesVisitor.java @@ -13,7 +13,7 @@ import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; -public class BindTypeParametersToTypeArgumentsVisitor extends AbstractNopTypeVisitor { +public class BindTypesToTypesVisitor extends AbstractNopTypeVisitor { protected TypeArgumentToTypeVisitor typeArgumentToTypeVisitor = new TypeArgumentToTypeVisitor(); protected BindTypeArgumentsToTypeArgumentsVisitor bindTypeArgumentsToTypeArgumentsVisitor = new BindTypeArgumentsToTypeArgumentsVisitor(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/DeclaredSyntheticLocalVariableVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/DeclaredSyntheticLocalVariableVisitor.java index 6eed696d..e98a4f6f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/DeclaredSyntheticLocalVariableVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/DeclaredSyntheticLocalVariableVisitor.java @@ -94,7 +94,6 @@ public void visit(NewArray expression) { @Override public void visit(NewExpression expression) { - safeAccept(expression.getNonWildcardTypeArguments()); safeAccept(expression.getParameters()); safeAccept(expression.getBodyDeclaration()); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java index 1c107506..1f2d1c36 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeParameterVisitor.java @@ -21,20 +21,20 @@ public void init(Map bindings, Map typeB } @Override - public void visit(TypeParameter type) { - bindings.put(type.getIdentifier(), null); + public void visit(TypeParameter parameter) { + bindings.put(parameter.getIdentifier(), null); } @Override - public void visit(TypeParameterWithTypeBounds type) { - bindings.put(type.getIdentifier(), null); - typeBounds.put(type.getIdentifier(), type.getTypeBounds()); + public void visit(TypeParameterWithTypeBounds parameter) { + bindings.put(parameter.getIdentifier(), null); + typeBounds.put(parameter.getIdentifier(), parameter.getTypeBounds()); } @Override - public void visit(TypeParameters types) { - for (TypeParameter typeParameter : types) { - typeParameter.accept(this); + public void visit(TypeParameters parameters) { + for (TypeParameter parameter : parameters) { + parameter.accept(this); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFirstLineNumberVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFirstLineNumberVisitor.java index a6c40da5..91920497 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFirstLineNumberVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFirstLineNumberVisitor.java @@ -66,7 +66,6 @@ public void visit(Statements statements) { @Override public void visit(NewArray expression) { lineNumber = expression.getLineNumber(); } @Override public void visit(NewExpression expression) { lineNumber = expression.getLineNumber(); } @Override public void visit(NewInitializedArray expression) { lineNumber = expression.getLineNumber(); } - @Override public void visit(NewInnerExpression expression) { lineNumber = expression.getLineNumber(); } @Override public void visit(NullExpression expression) { lineNumber = expression.getLineNumber(); } @Override public void visit(ObjectTypeReferenceExpression expression) { lineNumber = expression.getLineNumber(); } @Override public void visit(ParenthesesExpression expression) { lineNumber = expression.getLineNumber(); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index ed9519fb..f8b5d3d2 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -355,7 +355,9 @@ public void visit(LongConstantExpression expression) { @Override public void visit(MethodInvocationExpression expression) { Expression exp = expression.getExpression(); + BaseTypeArgument nonWildcardTypeArguments = expression.getNonWildcardTypeArguments(); BaseExpression parameters = expression.getParameters(); + boolean dot = false; if (exp.getClass() == ThisExpression.class) { // Nothing to do : do not print 'this.method(...)' @@ -366,14 +368,23 @@ public void visit(MethodInvocationExpression expression) { visit(expression, exp); tokens.addLineNumberToken(expression); tokens.add(TextToken.DOT); + dot = true; } } else { visit(expression, exp); tokens.addLineNumberToken(expression); tokens.add(TextToken.DOT); + dot = true; } tokens.addLineNumberToken(expression); + + if ((nonWildcardTypeArguments != null) && dot) { + tokens.add(TextToken.LEFTANGLEBRACKET); + nonWildcardTypeArguments.accept(this); + tokens.add(TextToken.RIGHTANGLEBRACKET); + } + tokens.add(new ReferenceToken(ReferenceToken.METHOD, expression.getInternalTypeName(), expression.getName(), expression.getDescriptor(), currentInternalTypeName)); tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); @@ -446,19 +457,12 @@ public void visit(NewInitializedArray expression) { @Override public void visit(NewExpression expression) { - BaseTypeArgument nonWildcardTypeArguments = expression.getNonWildcardTypeArguments(); BodyDeclaration bodyDeclaration = expression.getBodyDeclaration(); tokens.addLineNumberToken(expression); tokens.add(NEW); tokens.add(TextToken.SPACE); - if (nonWildcardTypeArguments != null) { - tokens.add(TextToken.LEFTANGLEBRACKET); - nonWildcardTypeArguments.accept(this); - tokens.add(TextToken.RIGHTANGLEBRACKET); - } - ObjectType objectType = expression.getObjectType(); if ((objectType.getTypeArguments() != null) && (bodyDeclaration == null) && (majorVersion >= 51)) { // (majorVersion >= Java 7) @@ -504,11 +508,6 @@ public void visit(NewExpression expression) { } } - @Override - public void visit(NewInnerExpression expression) { - visit((NewExpression) expression); - } - @Override public void visit(NullExpression expression) { tokens.addLineNumberToken(expression); @@ -731,7 +730,6 @@ public void visit(LongConstantExpression expression) { @Override public void visit(NewArray expression) { ExpressionVisitor.this.visit(expression); } @Override public void visit(NewExpression expression) { ExpressionVisitor.this.visit(expression); } @Override public void visit(NewInitializedArray expression) { ExpressionVisitor.this.visit(expression); } - @Override public void visit(NewInnerExpression expression) { ExpressionVisitor.this.visit(expression); } @Override public void visit(NullExpression expression) { ExpressionVisitor.this.visit(expression); } @Override public void visit(ObjectTypeReferenceExpression expression) { ExpressionVisitor.this.visit(expression); } @Override public void visit(ParenthesesExpression expression) { ExpressionVisitor.this.visit(expression); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java index 245ad48c..e7c25cbb 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java @@ -204,7 +204,6 @@ public void visit(NewArray expression) { @Override public void visit(NewExpression expression) { if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); - safeAccept(expression.getNonWildcardTypeArguments()); BaseType type = expression.getType(); @@ -219,19 +218,6 @@ public void visit(NewInitializedArray expression) { super.visit(expression); } - @Override - public void visit(NewInnerExpression expression) { - if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); - expression.getExpression().accept(this); - safeAccept(expression.getNonWildcardTypeArguments()); - - BaseType type = expression.getType(); - - type.accept(this); - safeAccept(expression.getParameters()); - safeAccept(expression.getBodyDeclaration()); - } - @Override public void visit(NullExpression expression) { if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java index d1919b35..c6b17b49 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SingleLineStatementVisitor.java @@ -284,11 +284,6 @@ public void visit(NewExpression expression) { } } - @Override - public void visit(NewInnerExpression expression) { - visit((NewExpression)expression); - } - protected void acceptListExpression(List list) { int size = list.size(); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index 243342d5..36046125 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -19,7 +19,6 @@ import java.util.HashMap; import java.util.List; -import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; public class TypeVisitor extends AbstractJavaSyntaxVisitor { @@ -204,15 +203,15 @@ public void visit(TypeParameterWithTypeBounds parameter) { @Override @SuppressWarnings("unchecked") - public void visit(TypeParameters list) { - int size = list.size(); + public void visit(TypeParameters parameters) { + int size = parameters.size(); if (size > 0) { - list.get(0).accept(this); + parameters.get(0).accept(this); for (int i=1; i> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.indexOf("/* 489: 489 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); @@ -800,7 +799,7 @@ public void testJdk150For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 345 */", "while (b < 10);"))); assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String str : paramArrayOfString)"))); assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String str : paramList)"))); - assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.matches(PatternMaker.make(": 423 */", "for (byte b = 0; b < 3; b++)"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -844,7 +843,7 @@ public void testJdk160For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.matches(PatternMaker.make(": 423 */", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -887,7 +886,7 @@ public void testIbmJ9For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.matches(PatternMaker.make(": 423 */", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 225a25d2..7739025d 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -36,12 +36,11 @@ public class JarFileToJavaSourceTest extends TestCase { protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); protected WriteTokenProcessor writer = new WriteTokenProcessor(); - // TODO In progress -// @Test -// public void testCommonsLang3() throws Exception { -// // Decompile and recompile 'commons-lang3-3.9.jar' -// test(org.apache.commons.lang3.JavaVersion.class); -// } + @Test + public void testCommonsCodec() throws Exception { + // Decompile and recompile 'commons-codec-1.13.jar' + test(org.apache.commons.codec.Charsets.class); + } @Test public void testCommonsCollections4() throws Exception { @@ -50,11 +49,18 @@ public void testCommonsCollections4() throws Exception { } @Test - public void testCommonsCodec() throws Exception { - // Decompile and recompile 'commons-codec-1.13.jar' - test(org.apache.commons.codec.Charsets.class); + public void testCommonsLang3() throws Exception { + // Decompile and recompile 'commons-lang3-3.9.jar' + test(org.apache.commons.lang3.JavaVersion.class); } + // TODO In progress +// @Test +// public void testJUnit4() throws Exception { +// // Decompile and recompile 'junit:junit:4.12' +// test(org.junit.Test.class); +// } + protected void test(Class clazz) throws Exception { test(new FileInputStream(Paths.get(clazz.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile())); } diff --git a/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java index 8098fd0e..ca3b2aa9 100644 --- a/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java @@ -87,6 +87,7 @@ public void testClassDeclaration() throws Exception { new NewExpression( 13, new ObjectType("java/util/Enumeration", "java.util.Enumeration", "Enumeration"), + "()V", new BodyDeclaration( "java/util/Enumeration", new MemberDeclarations( From 68d63d2a1908480a749624cf75f16432465c8a45 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 25 Dec 2019 12:48:22 +0100 Subject: [PATCH 121/211] Update configuration parsing --- .../jd/core/v1/service/layouter/LayoutFragmentProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java b/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java index 89f80ce4..a0726505 100644 --- a/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java +++ b/src/main/java/org/jd/core/v1/service/layouter/LayoutFragmentProcessor.java @@ -38,7 +38,7 @@ public void process(Message message) throws Exception { boolean showBridgeAndSynthetic = message.getHeader("showBridgeAndSynthetic", Boolean.FALSE); Map configuration = message.getHeader("configuration"); Object realignLineNumbersConfiguration = (configuration == null) ? "false" : configuration.get("realignLineNumbers"); - boolean realignLineNumbers = (realignLineNumbersConfiguration == null) ? false : !"false".equals(realignLineNumbersConfiguration.toString()); + boolean realignLineNumbers = (realignLineNumbersConfiguration == null) ? false : "true".equals(realignLineNumbersConfiguration.toString()); List fragments = message.getBody(); From a5c0ef6d9d51ef00ecc09bcb57b07e66c9dae2f9 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 25 Dec 2019 12:54:42 +0100 Subject: [PATCH 122/211] Update layouter --- .../javasyntaxtojavafragment/util/JavaFragmentFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java index ccbb6bca..dd64a568 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java @@ -36,7 +36,7 @@ public static void addEndArrayInitializer(List fragments, StartBlockFr } public static void addEndSingleStatementMethodBody(List fragments, StartBodyFragment start) { - fragments.add(new EndBodyFragment(0, 0, 1, 8, "End single statement method body", start)); + fragments.add(new EndBodyFragment(0, 1, 1, 8, "End single statement method body", start)); } public static void addEndMethodBody(List fragments, StartBodyFragment start) { @@ -145,7 +145,7 @@ public static void addNewLineBetweenArrayInitializerBlock(List fragmen } public static StartBodyFragment addStartSingleStatementMethodBody(List fragments) { - StartBodyFragment fragment = new StartBodyFragment(0, 0, 2, 9, "Start single statement method body"); + StartBodyFragment fragment = new StartBodyFragment(0, 1, 2, 9, "Start single statement method body"); fragments.add(fragment); return fragment; } From 8bc1e8f8f27022b40abebc6771b038b8e79b53cc Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 25 Dec 2019 15:01:20 +0100 Subject: [PATCH 123/211] Update tests --- .../java/org/jd/core/v1/ClassFileToJavaSourceTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 82c3b541..9750c6fe 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -2637,9 +2637,12 @@ public void testJdk901InterfaceWithDefaultMethods() throws Exception { assertTrue(source.matches(PatternMaker.make(": 24 */", "return unsafeGetZoneId(zoneString);"))); assertTrue(source.matches(PatternMaker.make(": 26 */", "System.err.println(\"Invalid time zone: \" + zoneString + \"; using default time zone instead.\");"))); assertTrue(source.matches(PatternMaker.make(": 27 */", "return ZoneId.systemDefault();"))); - assertTrue(source.matches(PatternMaker.make(": 32 */", "default ZonedDateTime getZonedDateTime(String zoneString) { return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString)); }"))); - assertTrue(source.matches(PatternMaker.make(": 36 */", "private static ZoneId unsafeGetZoneId(String zoneString) { return ZoneId.of(zoneString); }"))); - assertTrue(source.matches(PatternMaker.make(": 40 */", "private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId) { return ZonedDateTime.of(localDateTime, zoneId); }"))); + assertTrue(source.matches(PatternMaker.make("default ZonedDateTime getZonedDateTime(String zoneString)"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString));"))); + assertTrue(source.matches(PatternMaker.make("private static ZoneId unsafeGetZoneId(String zoneString)"))); + assertTrue(source.matches(PatternMaker.make(": 36 */", "return ZoneId.of(zoneString);"))); + assertTrue(source.matches(PatternMaker.make("private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId)"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "return ZonedDateTime.of(localDateTime, zoneId);"))); assertTrue(source.indexOf("// Byte code:") == -1); From 3904abaec3aaeea37ba808320406f5e8daa4880b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 25 Dec 2019 15:02:02 +0100 Subject: [PATCH 124/211] Prepare version 1.1.3 --- README.md | 2 -- build.gradle | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 8de12f82..65682eda 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ JD-Core is a JAVA decompiler written in JAVA. [http://java-decompiler.github.io](http://java-decompiler.github.io) - JD-Core source code: [https://github.com/java-decompiler/jd-core](https://github.com/java-decompiler/jd-core) -- JD Maven repository: -[https://raw.github.com/java-decompiler/mvn-repo/master](https://raw.github.com/java-decompiler/mvn-repo/master) - JCenter Maven repository: [https://jcenter.bintray.com/](https://jcenter.bintray.com/) diff --git a/build.gradle b/build.gradle index 8cd1311d..0a8cd359 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile 'junit:junit:4.12' } -version='1.1.2' +version='1.1.3' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' From 51fd8e9034077ea8ee60248e83972fae662bee4d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 25 Dec 2019 15:21:36 +0100 Subject: [PATCH 125/211] Publish JD-Core 1.1.3 --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 0a8cd359..dc31f57c 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,7 @@ publishing { } bintray { + // Command: gradlew -Dbintray.user=XXX -Dbintray.key=YYY bintrayUpload user = System.getProperty('bintray.user') key = System.getProperty('bintray.key') publications = ['publicationJdCore'] From 16074c86a99d64f0656f97b848112e54af655631 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 12:28:25 +0100 Subject: [PATCH 126/211] Fix syntax errors in decompiled sources --- .../visitor/StatementVisitor.java | 9 ++++----- .../javasyntaxtojavafragment/visitor/TypeVisitor.java | 10 ++++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java index 8cf90334..0d1113a6 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/StatementVisitor.java @@ -15,7 +15,6 @@ import org.jd.core.v1.model.javasyntax.expression.Expression; import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.BaseType; -import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.token.*; import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.util.JavaFragmentFactory; @@ -610,17 +609,17 @@ protected void visitTryStatement(TryStatement statement, StartStatementsBlockFra for (TryStatement.CatchClause cc : statement.getCatchClauses()) { JavaFragmentFactory.addEndStatementsBlock(fragments, group); - ObjectType type = cc.getType(); + BaseType type = cc.getType(); tokens = new Tokens(); tokens.add(CATCH); tokens.add(TextToken.SPACE_LEFTROUNDBRACKET); - tokens.add(newTypeReferenceToken(type, currentInternalTypeName)); + type.accept(this); if (cc.getOtherTypes() != null) { - for (ObjectType otherType : cc.getOtherTypes()) { + for (BaseType otherType : cc.getOtherTypes()) { tokens.add(TextToken.VERTICALLINE); - tokens.add(newTypeReferenceToken(otherType, currentInternalTypeName)); + otherType.accept(this); } } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index 36046125..2df0765a 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -131,8 +131,14 @@ public void visit(InnerObjectType type) { // Build token for type reference tokens.add(new ReferenceToken(ReferenceToken.TYPE, type.getInternalName(), type.getName(), null, currentInternalTypeName)); - // Build token for type arguments - visitTypeArgumentList(type.getTypeArguments()); + if (majorVersion >= 49) { // (majorVersion >= Java 5) + // Build token for type arguments + BaseTypeArgument typeArguments = type.getTypeArguments(); + + if (typeArguments != null) { + visitTypeArgumentList(typeArguments); + } + } // Build token for dimension visitDimension(type.getDimension()); From 77a7be8f2891a7efecebbf68ace729a55467d876 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 13:47:54 +0100 Subject: [PATCH 127/211] Improve import research --- .../visitor/SearchImportsVisitor.java | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java index e7c25cbb..fbd58267 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java @@ -9,6 +9,7 @@ import org.jd.core.v1.model.javafragment.ImportsFragment; import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.CompilationUnit; import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.reference.AnnotationElementValue; @@ -23,7 +24,7 @@ public class SearchImportsVisitor extends AbstractJavaSyntaxVisitor { protected String internalPackagePrefix; protected ImportsFragment importsFragment = JavaFragmentFactory.newImportsFragment(); protected int maxLineNumber = 0; - protected HashSet mainTypeNames = new HashSet<>(); + protected HashSet typeNames = new HashSet<>(); protected HashSet internalTypeNames = new HashSet<>(); public SearchImportsVisitor(String mainInternalName) { @@ -31,25 +32,24 @@ public SearchImportsVisitor(String mainInternalName) { this.internalPackagePrefix = (index == -1) ? "" : mainInternalName.substring(0, index + 1); } - @Override - public void visit(AnnotationReference reference) { - super.visit(reference); - add(reference.getType()); + public ImportsFragment getImportsFragment() { + importsFragment.initLineCounts(); + return importsFragment; } - @Override - public void visit(AnnotationElementValue reference) { - super.visit(reference); - add(reference.getType()); + public int getMaxLineNumber() { + return maxLineNumber; + } + + public void visit(CompilationUnit compilationUnit) { + compilationUnit.getTypeDeclarations().accept(new TypeVisitor(typeNames)); + compilationUnit.getTypeDeclarations().accept(this); } @Override public void visit(BodyDeclaration declaration) { - if (mainTypeNames.isEmpty()) { - mainTypeNames.add(getTypeName(declaration.getInternalTypeName())); - declaration.accept(new MainTypeVisitor(mainTypeNames)); - } if (!internalTypeNames.contains(declaration.getInternalTypeName())) { + internalTypeNames.add(declaration.getInternalTypeName()); safeAccept(declaration.getMemberDeclarations()); } } @@ -66,13 +66,16 @@ protected static String getTypeName(String internalTypeName) { return internalTypeName; } - public ImportsFragment getImportsFragment() { - importsFragment.initLineCounts(); - return importsFragment; + @Override + public void visit(AnnotationReference reference) { + super.visit(reference); + add(reference.getType()); } - public int getMaxLineNumber() { - return maxLineNumber; + @Override + public void visit(AnnotationElementValue reference) { + super.visit(reference); + add(reference.getType()); } @Override @@ -125,13 +128,6 @@ public void visit(DoubleConstantExpression expression) { if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); } - @Override - public void visit(EnumDeclaration declaration) { - safeAccept(declaration.getInterfaces()); - safeAccept(declaration.getAnnotationReferences()); - safeAccept(declaration.getBodyDeclaration()); - } - @Override public void visit(FieldReferenceExpression expression) { if (maxLineNumber < expression.getLineNumber()) maxLineNumber = expression.getLineNumber(); @@ -280,27 +276,26 @@ protected void add(ObjectType type) { String descriptor = type.getDescriptor(); if (descriptor.charAt(descriptor.length()-1) == ';') { - String internalName = type.getInternalName(); - String qualifiedName = type.getQualifiedName(); + String internalTypeName = type.getInternalName(); - if (internalName.startsWith("java/lang/")) { - if (internalName.indexOf('/', 10) != -1) { // 10 = "java/lang/".length() - importsFragment.addImport(internalName, qualifiedName); + if (internalTypeName.startsWith("java/lang/")) { + if (internalTypeName.indexOf('/', 10) != -1) { // 10 = "java/lang/".length() + importsFragment.addImport(internalTypeName, type.getQualifiedName()); } - } else if (internalName.startsWith(internalPackagePrefix)) { - if (internalName.indexOf('/', internalPackagePrefix.length()) != -1) { - importsFragment.addImport(internalName, qualifiedName); + } else if (internalTypeName.startsWith(internalPackagePrefix)) { + if ((internalTypeName.indexOf('/', internalPackagePrefix.length()) != -1) && !typeNames.contains(getTypeName(internalTypeName))) { + importsFragment.addImport(internalTypeName, type.getQualifiedName()); } - } else if (!mainTypeNames.contains(getTypeName(internalName))) { - importsFragment.addImport(internalName, qualifiedName); + } else if (!typeNames.contains(getTypeName(internalTypeName))) { + importsFragment.addImport(internalTypeName, type.getQualifiedName()); } } } - protected static class MainTypeVisitor extends AbstractJavaSyntaxVisitor { + protected static class TypeVisitor extends AbstractJavaSyntaxVisitor { HashSet mainTypeNames; - public MainTypeVisitor(HashSet mainTypeNames) { + public TypeVisitor(HashSet mainTypeNames) { this.mainTypeNames = mainTypeNames; } From 76786eebba6a1fbbb649492dd2d790b6b71c707b Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 14:04:39 +0100 Subject: [PATCH 128/211] Improve import search --- .../visitor/SearchImportsVisitor.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java index fbd58267..60fd5ef7 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java @@ -26,6 +26,7 @@ public class SearchImportsVisitor extends AbstractJavaSyntaxVisitor { protected int maxLineNumber = 0; protected HashSet typeNames = new HashSet<>(); protected HashSet internalTypeNames = new HashSet<>(); + protected HashSet importTypeNames = new HashSet<>(); public SearchImportsVisitor(String mainInternalName) { int index = mainInternalName.lastIndexOf('/'); @@ -277,17 +278,23 @@ protected void add(ObjectType type) { if (descriptor.charAt(descriptor.length()-1) == ';') { String internalTypeName = type.getInternalName(); - - if (internalTypeName.startsWith("java/lang/")) { - if (internalTypeName.indexOf('/', 10) != -1) { // 10 = "java/lang/".length() - importsFragment.addImport(internalTypeName, type.getQualifiedName()); - } - } else if (internalTypeName.startsWith(internalPackagePrefix)) { - if ((internalTypeName.indexOf('/', internalPackagePrefix.length()) != -1) && !typeNames.contains(getTypeName(internalTypeName))) { + String typeName = getTypeName(internalTypeName); + + if (!importTypeNames.contains(typeName)) { + if (internalTypeName.startsWith("java/lang/")) { + if (internalTypeName.indexOf('/', 10) != -1) { // 10 = "java/lang/".length() + importsFragment.addImport(internalTypeName, type.getQualifiedName()); + importTypeNames.add(typeName); + } + } else if (internalTypeName.startsWith(internalPackagePrefix)) { + if ((internalTypeName.indexOf('/', internalPackagePrefix.length()) != -1) && !typeNames.contains(typeName)) { + importsFragment.addImport(internalTypeName, type.getQualifiedName()); + importTypeNames.add(typeName); + } + } else if (!typeNames.contains(typeName)) { importsFragment.addImport(internalTypeName, type.getQualifiedName()); + importTypeNames.add(typeName); } - } else if (!typeNames.contains(getTypeName(internalTypeName))) { - importsFragment.addImport(internalTypeName, type.getQualifiedName()); } } } From 3a10b27bce24d68532f5cf4ce202d38749d8d12c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 14:34:32 +0100 Subject: [PATCH 129/211] Fix syntax errors in decompiled sources --- .../javasyntaxtojavafragment/visitor/ExpressionVisitor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index f8b5d3d2..6000bbc4 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -170,6 +170,7 @@ public void visit(Expressions list) { int size = list.size(); if (size > 0) { + boolean ief = inExpressionFlag; Iterator iterator = list.iterator(); for (int i=size-1; i>0; i--) { @@ -183,6 +184,7 @@ public void visit(Expressions list) { inExpressionFlag = false; iterator.next().accept(this); + inExpressionFlag = ief; } } } From 636cf2869a742827b2804113ca928e28d6c2c5f8 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 17:28:21 +0100 Subject: [PATCH 130/211] Improve import search --- .../model/javafragment/ImportsFragment.java | 14 ++++++++-- .../visitor/SearchImportsVisitor.java | 27 ++++++++++--------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java index 44ca2601..6333a399 100644 --- a/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java +++ b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2019 Emmanuel Dupuy. + * Copyright (c) 2008, 2019 Emmanuel Dupuy. * This project is distributed under the GPLv3 license. * This is a Copyleft license that gives the user the right to use, * copy and modify the code freely for non-commercial purposes. @@ -14,7 +14,6 @@ import java.util.Comparator; import java.util.HashMap; - public class ImportsFragment extends FlexibleFragment implements JavaFragment { protected static final ImportCountComparator COUNT_COMPARATOR = new ImportCountComparator(); @@ -34,6 +33,17 @@ public void addImport(String internalName, String qualifiedName) { } } + public boolean incCounter(String internalName) { + Import imp = importMap.get(internalName); + + if (imp == null) { + return false; + } else { + imp.incCounter(); + return true; + } + } + public boolean isEmpty() { return importMap.isEmpty(); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java index 60fd5ef7..a1285658 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java @@ -278,22 +278,25 @@ protected void add(ObjectType type) { if (descriptor.charAt(descriptor.length()-1) == ';') { String internalTypeName = type.getInternalName(); - String typeName = getTypeName(internalTypeName); - if (!importTypeNames.contains(typeName)) { - if (internalTypeName.startsWith("java/lang/")) { - if (internalTypeName.indexOf('/', 10) != -1) { // 10 = "java/lang/".length() + if (!importsFragment.incCounter(internalTypeName)) { + String typeName = getTypeName(internalTypeName); + + if (!importTypeNames.contains(typeName)) { + if (internalTypeName.startsWith("java/lang/")) { + if (internalTypeName.indexOf('/', 10) != -1) { // 10 = "java/lang/".length() + importsFragment.addImport(internalTypeName, type.getQualifiedName()); + importTypeNames.add(typeName); + } + } else if (internalTypeName.startsWith(internalPackagePrefix)) { + if ((internalTypeName.indexOf('/', internalPackagePrefix.length()) != -1) && !typeNames.contains(typeName)) { + importsFragment.addImport(internalTypeName, type.getQualifiedName()); + importTypeNames.add(typeName); + } + } else if (!typeNames.contains(typeName)) { importsFragment.addImport(internalTypeName, type.getQualifiedName()); importTypeNames.add(typeName); } - } else if (internalTypeName.startsWith(internalPackagePrefix)) { - if ((internalTypeName.indexOf('/', internalPackagePrefix.length()) != -1) && !typeNames.contains(typeName)) { - importsFragment.addImport(internalTypeName, type.getQualifiedName()); - importTypeNames.add(typeName); - } - } else if (!typeNames.contains(typeName)) { - importsFragment.addImport(internalTypeName, type.getQualifiedName()); - importTypeNames.add(typeName); } } } From 6092b9320e151e5b3abc82bead84874c7e65023c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 17:50:02 +0100 Subject: [PATCH 131/211] Fix syntax errors in decompiled sources --- .../visitor/PopulateBindingsWithTypeArgumentVisitor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java index 565ae2b6..c5f7b12c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/PopulateBindingsWithTypeArgumentVisitor.java @@ -53,7 +53,7 @@ public void visit(TypeArguments arguments) { String typeName = type.getName(); if (bindings.containsKey(typeName)) { - TypeArgument typeArgument = bindings.get(type.getName()); + TypeArgument typeArgument = bindings.get(typeName); if (current != null) { if ((current.getClass() == GenericType.class) && !equals(contextualTypeBounds.get(typeName), typeBounds.get(((GenericType)current).getName()))) { @@ -102,7 +102,7 @@ protected TypeArgument checkTypeClassCheckDimensionAndReturnCurrentAsTypeArgumen ObjectType ot = (ObjectType) current; if ((ot.getTypeArguments() == null) && ot.getInternalName().equals(TYPE_CLASS.getInternalName())) { - return TYPE_CLASS_WILDCARD.createType(ot.getDimension()); + return TYPE_CLASS_WILDCARD.createType(ot.getDimension() - type.getDimension()); } return ot.createType(ot.getDimension() - type.getDimension()); From 96244797d5b725843157f0f82497fc76b44cf494 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 18:19:34 +0100 Subject: [PATCH 132/211] Fix syntax errors in decompiled sources --- .../visitor/AbstractUpdateExpressionVisitor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java index efc4335e..3a23d798 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AbstractUpdateExpressionVisitor.java @@ -196,7 +196,9 @@ public void visit(NewExpression expression) { // safeAccept(expression.getBodyDeclaration()); } - @Override public void visit(NewInitializedArray expression) {} + @Override public void visit(NewInitializedArray expression) { + safeAccept(expression.getArrayInitializer()); + } @Override public void visit(ParenthesesExpression expression) { From e0a957ddd7110b57c5ddc4237809ec0ad1e3349e Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Fri, 27 Dec 2019 18:32:00 +0100 Subject: [PATCH 133/211] Fix syntax errors in decompiled sources --- .../visitor/CompilationUnitVisitor.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index e9e65fb4..6c4f7163 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -13,8 +13,6 @@ import org.jd.core.v1.model.javasyntax.CompilationUnit; import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.BaseExpression; -import org.jd.core.v1.model.javasyntax.expression.Expression; -import org.jd.core.v1.model.javasyntax.expression.NewInitializedArray; import org.jd.core.v1.model.javasyntax.reference.*; import org.jd.core.v1.model.javasyntax.statement.BaseStatement; import org.jd.core.v1.model.javasyntax.type.*; @@ -115,7 +113,10 @@ public void visit(AnnotationReference reference) { public void visitAnnotationReference(AnnotationReference reference) { tokens.add(TextToken.AT); - tokens.add(newTypeReferenceToken(reference.getType(), currentInternalTypeName)); + + BaseType type = reference.getType(); + + type.accept(this); ElementValue elementValue = reference.getElementValue(); From 7f0150895d369535f56b2ebbd482675ec15599ea Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 28 Dec 2019 16:48:52 +0100 Subject: [PATCH 134/211] Fix bug in try-catch-finally reconstruction --- .../RemoveFinallyStatementsVisitor.java | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java index ac8d7216..4f703c2e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveFinallyStatementsVisitor.java @@ -20,6 +20,7 @@ public class RemoveFinallyStatementsVisitor implements StatementVisitor { protected LocalVariableMaker localVariableMaker; protected int statementCountInFinally; protected int statementCountToRemove; + protected boolean lastFinallyStatementIsATryStatement; public RemoveFinallyStatementsVisitor(LocalVariableMaker localVariableMaker) { this.localVariableMaker = localVariableMaker; @@ -28,6 +29,7 @@ public RemoveFinallyStatementsVisitor(LocalVariableMaker localVariableMaker) { public void init() { this.statementCountInFinally = 0; this.statementCountToRemove = 0; + this.lastFinallyStatementIsATryStatement = false; } @Override @@ -64,34 +66,40 @@ public void visit(Statements statements) { } // Remove 'finally' statements - declaredSyntheticLocalVariableVisitor.init(); - if (statementCountToRemove > 0) { - // Remove 'finally' statements - if (i > statementCountToRemove) { - List list = statements.subList(i - statementCountToRemove, i); - - for (Statement statement : list) { - statement.accept(declaredSyntheticLocalVariableVisitor); - } - - lastStatement.accept(declaredSyntheticLocalVariableVisitor); - list.clear(); - i -= statementCountToRemove; + if (!lastFinallyStatementIsATryStatement && (i > 0) && (stmts.get(i-1).getClass() == ClassFileTryStatement.class)) { + stmts.get(i-1).accept(this); statementCountToRemove = 0; + i--; } else { - List list = statements; + declaredSyntheticLocalVariableVisitor.init(); - for (Statement statement : list) { - statement.accept(declaredSyntheticLocalVariableVisitor); - } + // Remove 'finally' statements + if (i > statementCountToRemove) { + List list = statements.subList(i - statementCountToRemove, i); - list.clear(); - if (i < size) { - list.add(lastStatement); + for (Statement statement : list) { + statement.accept(declaredSyntheticLocalVariableVisitor); + } + + lastStatement.accept(declaredSyntheticLocalVariableVisitor); + list.clear(); + i -= statementCountToRemove; + statementCountToRemove = 0; + } else { + List list = statements; + + for (Statement statement : list) { + statement.accept(declaredSyntheticLocalVariableVisitor); + } + + list.clear(); + if (i < size) { + list.add(lastStatement); + } + statementCountToRemove -= i; + i = 0; } - statementCountToRemove -= i; - i = 0; } } @@ -152,11 +160,22 @@ public void visit(SwitchStatement statement) { @Override public void visit(TryStatement statement) { + boolean oldLastFinallyStatementIsTryStatement = lastFinallyStatementIsATryStatement; ClassFileTryStatement ts = (ClassFileTryStatement)statement; Statements tryStatements = (Statements)ts.getTryStatements(); Statements finallyStatements = (Statements)ts.getFinallyStatements(); - safeAccept(finallyStatements); + if (finallyStatements != null) { + switch (finallyStatements.size()) { + case 0: break; + case 1: finallyStatements.getFirst().accept(this); break; + default: for (Statement stmt : finallyStatements) stmt.accept(this); break; + } + + if ((statementCountInFinally == 0) && (finallyStatements.size() > 0)) { + lastFinallyStatementIsATryStatement = (finallyStatements.getLast().getClass() == ClassFileTryStatement.class); + } + } if (ts.isJsr() || (finallyStatements == null) || (finallyStatements.size() == 0)) { tryStatements.accept(this); @@ -168,13 +187,13 @@ public void visit(TryStatement statement) { statementCountInFinally += finallyStatementsSize; - removeFinallyStatements(tryStatements); + tryStatements.accept(this); statementCountToRemove = finallyStatementsSize; if (catchClauses != null) { for (TryStatement.CatchClause cc : catchClauses) { - removeFinallyStatements((Statements)cc.getStatements()); + cc.getStatements().accept(this); } } @@ -192,11 +211,11 @@ public void visit(TryStatement statement) { statementCountInFinally += finallyStatementsSize; statementCountToRemove += finallyStatementsSize; - removeFinallyStatements(tryStatements); + tryStatements.accept(this); if (catchClauses != null) { for (TryStatement.CatchClause cc : catchClauses) { - removeFinallyStatements((Statements)cc.getStatements()); + cc.getStatements().accept(this); } } @@ -207,20 +226,8 @@ public void visit(TryStatement statement) { ts.setFinallyStatements(null); } } - } - - public void removeFinallyStatements(Statements list) { - if ((list.size() == 1) && (list.get(0).getClass() == ClassFileTryStatement.class)) { - int oldStatementCountToRemove = statementCountToRemove; - assert list.getFirst().getClass() == ClassFileTryStatement.class; - - statementCountToRemove = 0; - list.accept(this); - statementCountToRemove = oldStatementCountToRemove; - } else { - list.accept(this); - } + lastFinallyStatementIsATryStatement = oldLastFinallyStatementIsTryStatement; } @Override public void visit(DoWhileStatement statement) { safeAccept(statement.getStatements()); } From 819160bb29fd00db1f827d3a2ef359e544a30a71 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 28 Dec 2019 17:35:51 +0100 Subject: [PATCH 135/211] Fix syntax errors in decompiled sources --- .../core/v1/model/javafragment/ImportsFragment.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java index 6333a399..02e6c18b 100644 --- a/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java +++ b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java @@ -13,6 +13,7 @@ import java.util.Collection; import java.util.Comparator; import java.util.HashMap; +import java.util.List; public class ImportsFragment extends FlexibleFragment implements JavaFragment { protected static final ImportCountComparator COUNT_COMPARATOR = new ImportCountComparator(); @@ -72,9 +73,15 @@ public Collection getImports() { imports.sort(COUNT_COMPARATOR); // Remove less used imports - imports.subList(lineCount, size).clear(); + List subList = imports.subList(lineCount, size); - return imports; + for (Import imp0rt : subList) { + importMap.remove(imp0rt.getInternalName()); + } + + subList.clear(); + + return imports; } else { return importMap.values(); } From 3639a05f6de55963caf96aa220bbe799b8f5523c Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 11:51:46 +0100 Subject: [PATCH 136/211] Fix display of unicode characters --- .../util/CharacterUtil.java | 19 ++++++++++++++++++- .../jd/core/v1/printer/PlainTextPrinter.java | 16 ++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java index edc58412..0b440f96 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java @@ -28,7 +28,24 @@ public static String escapeChar(int c) { return "\\'"; default: if (c < ' ') { - return "\\0" + ((char)('0' + (c >> 3))) + ((char)('0' + (c & 7))); + return "\\0" + ((char) ('0' + (c >> 3))) + ((char) ('0' + (c & 7))); + } else if (c > 127) { + char[] buffer = new char[6]; + + buffer[0] = '\\'; + buffer[1] = 'u'; + + int h = (c >> 12); + + buffer[2] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); + h = (c >> 8) & 15; + buffer[3] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); + h = (c >> 4) & 15; + buffer[4] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); + h = (c) & 15; + buffer[5] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); + + return new String(buffer); } else { return String.valueOf((char)c); } diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java index b5022740..7a8bf9ea 100644 --- a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java +++ b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java @@ -65,16 +65,16 @@ public void printText(String text) { if (c < 128) { sb.append(c); } else { - int h = (c >> 24); + int h = (c >> 12); sb.append("\\u"); - sb.append((h <= 9) ? (h + '0') : (h + 'A')); - h = (c >> 16) & 255; - sb.append((h <= 9) ? (h + '0') : (h + 'A')); - h = (c >> 8) & 255; - sb.append((h <= 9) ? (h + '0') : (h + 'A')); - h = (c) & 255; - sb.append((h <= 9) ? (h + '0') : (h + 'A')); + sb.append((char)((h <= 9) ? (h + '0') : (h + ('A' - 10)))); + h = (c >> 8) & 15; + sb.append((char)((h <= 9) ? (h + '0') : (h + ('A' - 10)))); + h = (c >> 4) & 15; + sb.append((char)((h <= 9) ? (h + '0') : (h + ('A' - 10)))); + h = (c) & 15; + sb.append((char)((h <= 9) ? (h + '0') : (h + ('A' - 10)))); } } } else { From f4b10725108e635449e7d0cbcf02b462c4131dc4 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 12:18:46 +0100 Subject: [PATCH 137/211] Fix display of unicode characters --- .../util/CharacterUtil.java | 43 +++++++++++-------- .../jd/core/v1/printer/PlainTextPrinter.java | 2 +- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java index 0b440f96..51d30ff8 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/CharacterUtil.java @@ -26,29 +26,38 @@ public static String escapeChar(int c) { return "\\t"; case '\'': return "\\'"; + case 173: // SOFT HYPHEN + return unicode(c); default: if (c < ' ') { return "\\0" + ((char) ('0' + (c >> 3))) + ((char) ('0' + (c & 7))); - } else if (c > 127) { - char[] buffer = new char[6]; + } + if (c < 127) { + return String.valueOf((char)c); + } + if (c < 161) { + return unicode(c); + } + return String.valueOf((char)c); + } + } - buffer[0] = '\\'; - buffer[1] = 'u'; + private static String unicode(int c) { + char[] buffer = new char[6]; - int h = (c >> 12); + buffer[0] = '\\'; + buffer[1] = 'u'; - buffer[2] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); - h = (c >> 8) & 15; - buffer[3] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); - h = (c >> 4) & 15; - buffer[4] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); - h = (c) & 15; - buffer[5] = (char)((h <= 9) ? (h + '0') : (h + ('A' - 10))); + int h = (c >> 12); - return new String(buffer); - } else { - return String.valueOf((char)c); - } - } + buffer[2] = (char) ((h <= 9) ? (h + '0') : (h + ('A' - 10))); + h = (c >> 8) & 15; + buffer[3] = (char) ((h <= 9) ? (h + '0') : (h + ('A' - 10))); + h = (c >> 4) & 15; + buffer[4] = (char) ((h <= 9) ? (h + '0') : (h + ('A' - 10))); + h = (c) & 15; + buffer[5] = (char) ((h <= 9) ? (h + '0') : (h + ('A' - 10))); + + return new String(buffer); } } diff --git a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java index 7a8bf9ea..d493af24 100644 --- a/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java +++ b/src/test/java/org/jd/core/v1/printer/PlainTextPrinter.java @@ -62,7 +62,7 @@ public void printText(String text) { for(int i=0, len=text.length(); i> 12); From 646e4c05433dbc8d9b54b69d58e59ba36f52f1da Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 13:11:07 +0100 Subject: [PATCH 138/211] Improve control flows recognition --- .../util/ControlFlowGraphReducer.java | 28 ++++++++++++++++--- .../util/StatementMaker.java | 25 +++++++---------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 29de4a61..279bba13 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -141,17 +141,20 @@ protected static boolean reduceConditionalBranch(BasicBlock basicBlock) { if (nextNext == branchNext) { if (nextLast.matchType(TYPE_GOTO_IN_TERNARY_OPERATOR|TYPE_TERNARY_OPERATOR)) { createIfElse(TYPE_TERNARY_OPERATOR, basicBlock, next, nextLast, branch, branchLast, nextNext); + return true; } else { createIfElse(TYPE_IF_ELSE, basicBlock, next, nextLast, branch, branchLast, nextNext); + return true; } } else { - if ((nextNext.getFromOffset() < maxOffset) && (nextNext.getPredecessors().size() == 1)) { + if ((nextNext.getFromOffset() < branch.getFromOffset()) && (nextNext.getPredecessors().size() == 1)) { createIf(basicBlock, next, nextNext, branch); - } else { - createIfElse(TYPE_IF_ELSE, basicBlock, next, nextLast, branch, branchLast.getNext(), nextNext); + return true; + } else if (((nextNext.getFromOffset() > branch.getFromOffset()) && branchNext.matchType(GROUP_END))) { + createIfElse(TYPE_IF_ELSE, basicBlock, next, nextLast, branch, branchNext, nextNext); + return true; } } - return true; } } @@ -1063,6 +1066,8 @@ protected static boolean reduceLoop(BitSet visited, BasicBlock basicBlock, BitSe reduced = reduce(visited, basicBlock.getSub1(), jsrTargets); if (updateBasicBlock != null) { + removeLastContinueLoop(basicBlock.getSub1().getSub1()); + BasicBlock ifBasicBlock = basicBlock.getControlFlowGraph().newBasicBlock(TYPE_IF, basicBlock.getSub1().getFromOffset(), basicBlock.getToOffset()); ifBasicBlock.setCondition(END); @@ -1103,6 +1108,21 @@ protected static boolean reduceLoop(BitSet visited, BasicBlock basicBlock, BitSe return reduced & reduce(visited, basicBlock.getNext(), jsrTargets); } + protected static void removeLastContinueLoop(BasicBlock basicBlock) { + BitSet visited = new BitSet(); + BasicBlock next = basicBlock.getNext(); + + while (!next.matchType(GROUP_END) && (visited.get(next.getIndex()) == false)) { + visited.set(next.getIndex()); + basicBlock = next; + next = basicBlock.getNext(); + } + + if (next == LOOP_CONTINUE) { + basicBlock.setNext(END); + } + } + protected static BasicBlock getLastConditionalBranch(BitSet visited, BasicBlock basicBlock) { if (!basicBlock.matchType(GROUP_END) && (visited.get(basicBlock.getIndex()) == false)) { visited.set(basicBlock.getIndex()); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 71dbf693..5d0fb1d3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -266,11 +266,11 @@ protected void makeStatements(WatchDog watchdog, BasicBlock basicBlock, Statemen } } - protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, Statements updateStatements) { + protected Statements makeSubStatements(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps, BasicBlock updateBasicBlock) { Statements subStatements = makeSubStatements(watchdog, basicBlock, statements, jumps); - if (updateStatements != null) { - subStatements.addAll(updateStatements); + if (updateBasicBlock != null) { + subStatements.addAll(makeSubStatements(watchdog, updateBasicBlock, statements, jumps)); } return subStatements; @@ -612,10 +612,10 @@ protected void parseIf(WatchDog watchdog, BasicBlock basicBlock, Statements stat @SuppressWarnings("unchecked") protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements statements, Statements jumps) { BasicBlock sub1 = basicBlock.getSub1(); - Statements updateStatements = null; + BasicBlock updateBasicBlock = null; if ((sub1.getType() == TYPE_IF) && (sub1.getCondition() == END)) { - updateStatements = makeSubStatements(watchdog, sub1.getNext(), statements, jumps); + updateBasicBlock = sub1.getNext(); sub1 = sub1.getSub1(); } @@ -627,7 +627,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st makeStatements(watchdog, ifBB.getCondition(), statements, jumps); statements.add(LoopStatementMaker.makeLoop( typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), - makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateStatements), jumps)); + makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateBasicBlock), jumps)); makeStatements(watchdog, basicBlock.getNext(), statements, jumps); return; } @@ -648,7 +648,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st makeStatements(watchdog, ifBB.getCondition(), statements, jumps); statements.add(LoopStatementMaker.makeLoop( typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), - makeSubStatements(watchdog, ifBB.getNext(), statements, jumps, updateStatements), jumps)); + makeSubStatements(watchdog, ifBB.getNext(), statements, jumps, updateBasicBlock), jumps)); } makeStatements(watchdog, basicBlock.getNext(), statements, jumps); @@ -673,21 +673,21 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st if ((sub1.getType() == TYPE_LOOP) && (sub1.getNext() == last) && (countStartLoop(sub1.getSub1()) == 0)) { changeEndLoopToStartLoop(new BitSet(), sub1.getSub1()); - subStatements = makeSubStatements(watchdog, sub1.getSub1(), statements, jumps, updateStatements); + subStatements = makeSubStatements(watchdog, sub1.getSub1(), statements, jumps, updateBasicBlock); assert subStatements.getLast() == ContinueStatement.CONTINUE : "StatementMaker.parseLoop(...) : unexpected basic block for create a do-while loop"; subStatements.removeLast(); } else { createDoWhileContinue(last); - subStatements = makeSubStatements(watchdog, sub1, statements, jumps, updateStatements); + subStatements = makeSubStatements(watchdog, sub1, statements, jumps, updateBasicBlock); } makeStatements(watchdog, last.getCondition(), subStatements, jumps); statements.add(LoopStatementMaker.makeDoWhileLoop(basicBlock, last, stack.pop(), subStatements, jumps)); } else { // Infinite loop - statements.add(LoopStatementMaker.makeLoop(basicBlock, statements, makeSubStatements(watchdog, sub1, statements, jumps, updateStatements), jumps)); + statements.add(LoopStatementMaker.makeLoop(basicBlock, statements, makeSubStatements(watchdog, sub1, statements, jumps, updateBasicBlock), jumps)); } makeStatements(watchdog, basicBlock.getNext(), statements, jumps); @@ -1044,9 +1044,4 @@ public void visit(MethodDeclaration declaration) { found |= declaration.getName().equals(name); } } - - protected static class NopBitSet extends BitSet { - @Override public boolean get(int var1) { return false; } - @Override public void set(int var1) {} - } } From 130df93d49deaed74118a753f27972f31949e88e Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 13:44:26 +0100 Subject: [PATCH 139/211] Update tests --- build.gradle | 4 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 60 +++++++++--------- .../resources/java/org/jd/core/test/For.java | 14 +++- ...data-java-eclipse-java-compiler-3.13.0.zip | Bin 38140 -> 39073 bytes .../resources/zip/data-java-ibm-j9_vm.zip | Bin 44420 -> 44996 bytes .../resources/zip/data-java-jdk-1.5.0.zip | Bin 39848 -> 40320 bytes .../resources/zip/data-java-jdk-1.6.0.zip | Bin 55749 -> 56357 bytes .../zip/data-java-jdk-1.7.0-no-debug-info.zip | Bin 7934 -> 7969 bytes .../resources/zip/data-java-jdk-1.7.0.zip | Bin 64633 -> 64709 bytes .../resources/zip/data-java-jdk-1.8.0.zip | Bin 67600 -> 67965 bytes .../resources/zip/data-java-jdk-10.0.2.zip | Bin 21529 -> 21956 bytes .../resources/zip/data-java-jdk-9.0.1.zip | Bin 21514 -> 21941 bytes 12 files changed, 46 insertions(+), 32 deletions(-) diff --git a/build.gradle b/build.gradle index dc31f57c..1d989da2 100644 --- a/build.gradle +++ b/build.gradle @@ -8,10 +8,12 @@ dependencies { testCompile 'commons-codec:commons-codec:1.13' testCompile 'org.apache.commons:commons-collections4:4.1' testCompile 'org.apache.commons:commons-lang3:3.9' + testCompile 'com.squareup:javapoet:1.11.1' + testCompile 'org.jsoup:jsoup:1.12.1' testCompile 'junit:junit:4.12' } -version='1.1.3' +version='1.1.4' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 9750c6fe..a56bdb49 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -717,7 +717,7 @@ public void testJdk170For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 403 */", "for (String s : list)"))); assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.indexOf("/* 489: 489 */") != -1); + assertTrue(source.indexOf("/* 524: 524 */") != -1); assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors @@ -791,16 +791,16 @@ public void testJdk150For() throws Exception { printSource(source); // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 16 */", "for (byte b = 0; b < 10; b++)"))); - assertTrue(source.matches(PatternMaker.make(": 84 */", "while (paramInt < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 269 */", "for (paramInt = 0; paramInt < 10; paramInt++)"))); - assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do {"))); - assertTrue(source.matches(PatternMaker.make(": 345 */", "while (b < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String str : paramArrayOfString)"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String str : paramList)"))); - assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 423 */", "for (byte b = 0; b < 3; b++)"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (paramInt < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 273 */", "for (paramInt = 0; paramInt < 10; paramInt++)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 349 */", "while (b < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String str : paramArrayOfString)"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String str : paramList)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "for (byte b = 0; b < 3; b++)"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -835,16 +835,16 @@ public void testJdk160For() throws Exception { printSource(source); // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 16 */", "for (int i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 84 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 269 */", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int j : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do {"))); - assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 423 */", "for (int i = 0; i < 3; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 273 */", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 349 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -879,15 +879,15 @@ public void testIbmJ9For() throws Exception { printSource(source); // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 84 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 269 */", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 306 */", "for (int j : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("/* 343: 0 */", "do"))); - assertTrue(source.matches(PatternMaker.make(": 345 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 381 */", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 407 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 423 */", "for (int i = 0; i < 3; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 273 */", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do"))); + assertTrue(source.matches(PatternMaker.make(": 349 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); assertTrue(source.indexOf("// Byte code:") == -1); diff --git a/src/test/resources/java/org/jd/core/test/For.java b/src/test/resources/java/org/jd/core/test/For.java index 975778f8..8a26509d 100644 --- a/src/test/resources/java/org/jd/core/test/For.java +++ b/src/test/resources/java/org/jd/core/test/For.java @@ -473,7 +473,6 @@ public static void forIfContinue() { public void forIfIfContinue() { for (int i=0; i<100; i++) { if (i == 1) { - // Empty line if (i != 2) { continue; } @@ -482,6 +481,19 @@ public void forIfIfContinue() { } } + public void forIfIfContinue2() { + for (int i=0; i<100; i++) { + if (i == 1) { + if (i != 2) { + i = 3; + continue; + } + i = 4; + } + i += 42; + } + } + public void forIterator(Map map) { for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry entry = it.next(); diff --git a/src/test/resources/zip/data-java-eclipse-java-compiler-3.13.0.zip b/src/test/resources/zip/data-java-eclipse-java-compiler-3.13.0.zip index b79d9d12f4be68167c476fd977544b9b0abb9085..c4131fce505acfbd9a305613bd00fdc621e71904 100644 GIT binary patch delta 3801 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 delta 2869 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 UK9G}f1{0HiuRjJrn*aa+06O5_A^-pY diff --git a/src/test/resources/zip/data-java-jdk-1.5.0.zip b/src/test/resources/zip/data-java-jdk-1.5.0.zip index 4052a6fde990b1a808901d4ac56fa4c5fd890835..a7656889cefeca557e1097bed86c7ad92391f2a6 100644 GIT binary patch delta 3373 zcmV+|4bt+cw*r8>0Taur!xY>|Y8tjBV&9F2GW{{MIPZ(@g&KQr&o+%f0;I9@(Zu;N4;PO{--D^9WDR5|xF8&=zJy2Locjy#-c$5}XA zU1!BPa>lti*r zx|exrNeg;<`@G6Re?TC!OX>8w1MZN=@0;uEQf=81CNels35E{p>vD&z0g4v)|t*kV8vL*c~;HksuzU<9$!ygqq-_pZg*gnKyH6oQ_P&UWh<1<2(B|S;{b)w zzQ}?|0+vlpTp*AlbETU*#Fpu~Ksvgof5~!>OzQkZqYPUc;R;56MU#{eaeZze;8vw} zB)FqWb!hXX#~k_mp}9uT(q+c`x|Be$(;rX^V`|4d0sDeuI+Z?ISV7M5bT5?Zbzf7; zI+~^~)vAA|d%oWn^7z8CTGer^CBtN?(aI{MuxiyTj@^+Kcb}@)#wqgxiu*{zr^N8v z7x}}1PGzAQKO5yulhd4-ju}>5@5BwbkwSwZcOYcNfDbxE(ZWGazX zD{gV(R@`RA?M~c*JDu2sb~<1VsDNVY=6=7%}67PD!~dJ6-%yoY;)J zoVXkJSaGitgV@4oMc2>wx`RQv;67$?)NJ5cG33NnY@^$q{@&gaB@pljq^~zyalaD} zV7nC$MwUiHIcb3}Br`ZgYn@F#pAt~16p}rJb|)SNOFz%-n^ksu_NOkA`NT+YaK$pY~zN}sIyebmokTms3@jZB?I3du9$ zqC}JQDb}C`VX@mQ3qLiW^!iuIj=QfHkd&1? z2upH(QHH%AnR1-M@oFIkhQE=cRF0xxg-GQy3pQjU13AcNJD$%{6mZ6DgWv#-pfrZS zX2$<^G<+BFOE8w6=CLj2?Q1gs3)Fua_)Gq+1LI-kvy24gu%nVrR3V@3cm}dmh2I6c zY9#w>B$IWLzef@AVHPQBF@|utY+aZ`FX}jBH^YZ|4L(2WLmc#v24WU0d^Qqs4~m}4 z@g96L#}HbpA?4~wBjZp_GM@{H(?rMjrnSycv!{mPGDUQZjx{j+o#7*WO5uOAl}P&$ zX@BH%$BVFtZ|ehiQH4>gpG?6zj8I1~ zSZn(GtW*@IIE$QE;&>MTmc89p;QZ45GvTD^Vobk0H^qtfu2gb^^(cC)vp)JB736 z8e~WQS2ETUpQ}lB27711iL*$0Hc8JT={eX5=aP60i7(`edH*-@B_zI#y|pA>N88&=69ttsJAT9C6(PT=yU? zdl`(gv~}60h@=h-|FYRs8;^4J;~0l0Xx-aDsDnjCDAExu_uJc(liQjrwrfB?n}MDt z(6g+G=V)y*fOgfgB0qmND~cLNmGdG|UgGECWm@+!PZQKc|!dco{MwRszk>26S_%5x@#{Sf3an90_MqU3t*MEpid_-%Dp=7GI zK0T^rfW!Fh{gg{Tr=`_cHbp!69Qv}vMPG5zH?*`Fi}uwvV#@3nyDIAz3oYW5z z9LQM*VX@}ZNg97;U3>vWZV*n*pL8|y&Q{qUs~6{6QDXj<&0EhzjEOzp#8?W*M25&h zzQ{(2$iqaDL!Wa|Nqdbb#2it?6-x{;Cum}JGl`jK7PC2C$~$H$6HHRZQ%VV?OrVsB zlrjku#AL>%6y>x}7v=nQvVtoPM!P0uEiCE>eo6dwFqeN@ogy~TSTu+XmHZ2}q^$D5 zXh?1>cJ;$mQ9P~IlAL4NsHR1ZMNUoT)Q@$Y<(rJnng$2E(RM?pMDGg)$V7 zH|fF*`?bTrjdBAJ2a&m*%uA8Swpbj>+<-LSB##F_^kFrrKC0dm>XdnN+?Vh3kjE zAC0qOA;=TYPglXE3G!{l5=&f~~=Jkod} zJY3^ElbkXc+jP$IXtL#26xYm=J6K@h3pLHY_>0$xVoH(5?nxAL3JS!jn80?5IGt5- z2KHdPP@IicaSmr4VH{Q$v6TmYyCF(FtePwI!>U3*tXepuGICh`ojIe)JD*F}ur4md zRB?Y1&yY(f>r&RmW!O)w#lhl=m;=sj?3bd+oLxSMaf8Ud4>?1~9Z5r;rXfF~p@Kd0 zcCF`DUBw7p&2+qmXU7I^*R?!b`zdglv0e2fRDVrkIhJqlS3jENMKyZqeQo;Uh#TnG zjmTu1CkD832|BeHFC~%`zcZ0i`}y5ysoa0ml8wUq;8LN!+J=Jmtl}*g&ubAC+F7;* zaf)w+RoqTT?|?(x38&bEEZXwL-RR;R3+EQ_si0fa?jf_4?Tq9G*OjQOXsz1LqpUV1 zCnd+iY^ushnO2+XTE|a6uZby?@HwZYSQ=cnnRaUnlEe^F#a5nX+j!*O&ya29&OLv~ zkUfNI@fc_I7`wDatEzottE#IXv-Oj|@XE*yEnW648zuiZ^TDQ;-m?kmLjotePch2R zaQ~jA_s>z(^ZXROKtV4um0sc=zJhwbpC?|!KH_z*TyBVK)34p!1u3eaNS^FPDI27U z)YYO~-HT7n$?_%%-$J^0n<0OP=lXwp$fs?*_<*xK(cjH9@QE6Du>>D0!ELGayt!NJ zb%GDg1@SQnJ|V%UB>0TU@j3J73ufn6^zLI8io6!Bz>yk}o2`1eV7~7pc>gYmxmoP2 z-z+AyRt<3}|9a_IhcsFz3h-NR`c+VTM}NL2%nv-1f8-xJcQAnRvgAdtMz?<*$tvAS zV@DfY6)c7$DqJimz)|7Ks#r9DvXN$1 zvcn5dRb;kI#w3PlW8&u5BAwk|8LHp7`M)EZ!OlnGPDtX zW80R}3%}I?W80R}3%}I?W80R}3%}Kq-Iyx^(^!+i1rw7UnOy?bS(Cv96O)gbS^`&K zlfeZOlm3}t0<~n5!37hO3}Y3Oh?-6UfN7J#1rw9&nqvZhfs?@n6O&_`KL$LD00000 DY#@DN delta 2913 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 diff --git a/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip b/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip index c3aa8b73da81da94647ad4d89acaaf6fec2cacdd..2050267eaf6e28ab222fce7b3b269567f7b6ae84 100644 GIT binary patch delta 2701 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 YmmVwv(ixKx8X}YD9yA8L8UO$Q0FllQEdT%j diff --git a/src/test/resources/zip/data-java-jdk-1.7.0.zip b/src/test/resources/zip/data-java-jdk-1.7.0.zip index 9b25f85dea4fc59896d8ca0543d9a6b86f873993..dcc18957265294e17c79bafc67b8e39e4d36e0fe 100644 GIT binary patch delta 4676 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 delta 4578 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 iR4f8rJd;5p6O-&zZvrMjlR+XAlW Date: Mon, 30 Dec 2019 15:43:48 +0100 Subject: [PATCH 140/211] Fix syntax errors in decompiled sources --- .../util/ControlFlowGraphReducer.java | 100 +++++++++--------- 1 file changed, 48 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 279bba13..1ee771be 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -530,10 +530,8 @@ protected static boolean reduceSwitchDeclaration(BitSet visited, BasicBlock basi BasicBlock end = END; for (BasicBlock bb : ends) { - if (!bb.matchType(GROUP_END)) { - if ((end == END) || (end.getFromOffset() < bb.getFromOffset())) { - end = bb; - } + if ((end == END) || (end.getFromOffset() < bb.getFromOffset())) { + end = bb; } } @@ -1161,54 +1159,52 @@ protected static BasicBlock getLastConditionalBranch(BitSet visited, BasicBlock } protected static void visit(BitSet visited, BasicBlock basicBlock, int maxOffset, HashSet ends) { - if (!basicBlock.matchType(GROUP_END)) { - if (basicBlock.getFromOffset() >= maxOffset) { - ends.add(basicBlock); - } else if (visited.get(basicBlock.getIndex()) == false) { - visited.set(basicBlock.getIndex()); - - switch (basicBlock.getType()) { - case TYPE_CONDITIONAL_BRANCH: - case TYPE_JSR: - case TYPE_CONDITION: - visit(visited, basicBlock.getBranch(), maxOffset, ends); - case TYPE_START: - case TYPE_STATEMENTS: - case TYPE_GOTO: - case TYPE_GOTO_IN_TERNARY_OPERATOR: - case TYPE_LOOP: - visit(visited, basicBlock.getNext(), maxOffset, ends); - break; - case TYPE_TRY: - case TYPE_TRY_JSR: - case TYPE_TRY_ECLIPSE: - visit(visited, basicBlock.getSub1(), maxOffset, ends); - case TYPE_TRY_DECLARATION: - for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { - visit(visited, exceptionHandler.getBasicBlock(), maxOffset, ends); - } - visit(visited, basicBlock.getNext(), maxOffset, ends); - break; - case TYPE_IF_ELSE: - case TYPE_TERNARY_OPERATOR: - visit(visited, basicBlock.getSub2(), maxOffset, ends); - case TYPE_IF: - visit(visited, basicBlock.getSub1(), maxOffset, ends); - visit(visited, basicBlock.getNext(), maxOffset, ends); - break; - case TYPE_CONDITION_OR: - case TYPE_CONDITION_AND: - visit(visited, basicBlock.getSub1(), maxOffset, ends); - visit(visited, basicBlock.getSub2(), maxOffset, ends); - break; - case TYPE_SWITCH: - visit(visited, basicBlock.getNext(), maxOffset, ends); - case TYPE_SWITCH_DECLARATION: - for (SwitchCase switchCase : basicBlock.getSwitchCases()) { - visit(visited, switchCase.getBasicBlock(), maxOffset, ends); - } - break; - } + if (basicBlock.getFromOffset() >= maxOffset) { + ends.add(basicBlock); + } else if ((basicBlock.getIndex() >= 0) && (visited.get(basicBlock.getIndex()) == false)) { + visited.set(basicBlock.getIndex()); + + switch (basicBlock.getType()) { + case TYPE_CONDITIONAL_BRANCH: + case TYPE_JSR: + case TYPE_CONDITION: + visit(visited, basicBlock.getBranch(), maxOffset, ends); + case TYPE_START: + case TYPE_STATEMENTS: + case TYPE_GOTO: + case TYPE_GOTO_IN_TERNARY_OPERATOR: + case TYPE_LOOP: + visit(visited, basicBlock.getNext(), maxOffset, ends); + break; + case TYPE_TRY: + case TYPE_TRY_JSR: + case TYPE_TRY_ECLIPSE: + visit(visited, basicBlock.getSub1(), maxOffset, ends); + case TYPE_TRY_DECLARATION: + for (BasicBlock.ExceptionHandler exceptionHandler : basicBlock.getExceptionHandlers()) { + visit(visited, exceptionHandler.getBasicBlock(), maxOffset, ends); + } + visit(visited, basicBlock.getNext(), maxOffset, ends); + break; + case TYPE_IF_ELSE: + case TYPE_TERNARY_OPERATOR: + visit(visited, basicBlock.getSub2(), maxOffset, ends); + case TYPE_IF: + visit(visited, basicBlock.getSub1(), maxOffset, ends); + visit(visited, basicBlock.getNext(), maxOffset, ends); + break; + case TYPE_CONDITION_OR: + case TYPE_CONDITION_AND: + visit(visited, basicBlock.getSub1(), maxOffset, ends); + visit(visited, basicBlock.getSub2(), maxOffset, ends); + break; + case TYPE_SWITCH: + visit(visited, basicBlock.getNext(), maxOffset, ends); + case TYPE_SWITCH_DECLARATION: + for (SwitchCase switchCase : basicBlock.getSwitchCases()) { + visit(visited, switchCase.getBasicBlock(), maxOffset, ends); + } + break; } } } From a7e00d51333487efccc67776e28379dce4d0bf23 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 20:54:09 +0100 Subject: [PATCH 141/211] Fix syntax errors in decompiled sources --- .../TypeParametersToTypeArgumentsBinder.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 32fa0125..980f5e48 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -139,7 +139,7 @@ public void bindParameterTypesWithArgumentTypes(Type type, Expression expression } protected Type checkTypeArguments(Type type, AbstractLocalVariable localVariable) { - if (type.isObject()) { + if ((type != null) && type.isObject()) { ObjectType objectType = (ObjectType)type; if (objectType.getTypeArguments() != null) { @@ -191,7 +191,7 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { Type t = mie.getType(); - if (type.isObject() && t.isObject()) { + if ((type != null) && type.isObject() && t.isObject()) { ObjectType objectType = (ObjectType) type; ObjectType mieTypeObjectType = (ObjectType) t; t = typeMaker.searchSuperParameterizedType(objectType, mieTypeObjectType); @@ -212,7 +212,7 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { if (expressionType.isObject()) { ObjectType expressionObjectType = (ObjectType) expressionType; - if (bindingsContainsNull) { + if (bindings.isEmpty() || bindingsContainsNull) { expressionType = expressionObjectType.createType(null); } else { boolean statik = (expression.getClass() == ObjectTypeReferenceExpression.class); @@ -229,6 +229,14 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { expressionType = expressionObjectType.createType(bindings.get(typeParameters.getFirst().getIdentifier())); } } + } else if (expressionType.isGeneric()) { + if (bindings.isEmpty() || bindingsContainsNull) { + expressionType = null; + } else { + typeArgumentToTypeVisitor.init(); + bindings.get(expressionType.getName()).accept(typeArgumentToTypeVisitor); + expressionType = typeArgumentToTypeVisitor.getType(); + } } } } @@ -265,7 +273,7 @@ protected void bind(Type type, ClassFileNewExpression ne) { Type t = neObjectType; - if (type.isObject()) { + if ((type != null) && type.isObject()) { ObjectType objectType = (ObjectType)type; t = typeMaker.searchSuperParameterizedType(objectType, neObjectType); } @@ -527,7 +535,7 @@ public void visit(MethodInvocationExpression expression) { @Override public void visit(LocalVariableReferenceExpression expression) { - if (!type.isPrimitive()) { + if ((type != null) && !type.isPrimitive()) { AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); localVariable.typeOnLeft(contextualTypeBounds, checkTypeArguments(type, localVariable)); } @@ -541,9 +549,7 @@ public void visit(NewExpression expression) { @Override public void visit(CastExpression expression) { - assert TYPE_OBJECT.equals(type) || (type.getDimension() == expression.getType().getDimension()) : "TypeParametersToTypeArgumentsBinder.visit(CastExpression ce) : invalid array type"; - - if (type.isObject()) { + if ((type != null) && type.isObject()) { ObjectType objectType = (ObjectType)type; if ((objectType.getTypeArguments() != null) && !objectType.getTypeArguments().equals(WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT)) { From 9c0091cb37db494df15abfb3225fa34bcaa6a3d4 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 21:09:01 +0100 Subject: [PATCH 142/211] Fix syntax errors in decompiled sources --- .../util/TypeParametersToTypeArgumentsBinder.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 980f5e48..573a2a2a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -139,7 +139,7 @@ public void bindParameterTypesWithArgumentTypes(Type type, Expression expression } protected Type checkTypeArguments(Type type, AbstractLocalVariable localVariable) { - if ((type != null) && type.isObject()) { + if (type.isObject()) { ObjectType objectType = (ObjectType)type; if (objectType.getTypeArguments() != null) { @@ -191,7 +191,7 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { Type t = mie.getType(); - if ((type != null) && type.isObject() && t.isObject()) { + if (type.isObject() && t.isObject()) { ObjectType objectType = (ObjectType) type; ObjectType mieTypeObjectType = (ObjectType) t; t = typeMaker.searchSuperParameterizedType(objectType, mieTypeObjectType); @@ -231,7 +231,7 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { } } else if (expressionType.isGeneric()) { if (bindings.isEmpty() || bindingsContainsNull) { - expressionType = null; + expressionType = ObjectType.TYPE_OBJECT; } else { typeArgumentToTypeVisitor.init(); bindings.get(expressionType.getName()).accept(typeArgumentToTypeVisitor); @@ -273,7 +273,7 @@ protected void bind(Type type, ClassFileNewExpression ne) { Type t = neObjectType; - if ((type != null) && type.isObject()) { + if (type.isObject()) { ObjectType objectType = (ObjectType)type; t = typeMaker.searchSuperParameterizedType(objectType, neObjectType); } @@ -535,7 +535,7 @@ public void visit(MethodInvocationExpression expression) { @Override public void visit(LocalVariableReferenceExpression expression) { - if ((type != null) && !type.isPrimitive()) { + if (!type.isPrimitive()) { AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); localVariable.typeOnLeft(contextualTypeBounds, checkTypeArguments(type, localVariable)); } @@ -549,7 +549,9 @@ public void visit(NewExpression expression) { @Override public void visit(CastExpression expression) { - if ((type != null) && type.isObject()) { + assert TYPE_OBJECT.equals(type) || (type.getDimension() == expression.getType().getDimension()) : "TypeParametersToTypeArgumentsBinder.visit(CastExpression ce) : invalid array type"; + + if (type.isObject()) { ObjectType objectType = (ObjectType)type; if ((objectType.getTypeArguments() != null) && !objectType.getTypeArguments().equals(WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT)) { From f06bc3aa19eaeefba4e6bffcdcafc8180c2b2892 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 23:07:28 +0100 Subject: [PATCH 143/211] Fix syntax errors in decompiled sources --- .../util/LocalVariableMaker.java | 23 ++++- .../util/LoopStatementMaker.java | 97 +++++++++++++------ .../util/StatementMaker.java | 7 +- .../ChangeFrameOfLocalVariablesVisitor.java | 54 +++++++++++ 4 files changed, 146 insertions(+), 35 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/ChangeFrameOfLocalVariablesVisitor.java diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index c8ec38bb..bbbb1740 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -513,7 +513,19 @@ public void popFrame() { currentFrame = currentFrame.getParent(); } - protected Frame searchCommonParentFrame(Frame frame1, Frame frame2) { + protected static Frame searchCommonParentFrame(Frame frame1, Frame frame2) { + if (frame1 == frame2) { + return frame1; + } + + if (frame2.getParent() == frame1) { + return frame1; + } + + if (frame1.getParent() == frame2) { + return frame2; + } + HashSet set = new HashSet<>(); while (frame1 != null) { @@ -530,4 +542,13 @@ protected Frame searchCommonParentFrame(Frame frame1, Frame frame2) { return null; } + + public void changeFrame(AbstractLocalVariable localVariable) { + Frame frame = LocalVariableMaker.searchCommonParentFrame(localVariable.getFrame(), currentFrame); + + if (localVariable.getFrame() != frame) { + localVariable.getFrame().removeLocalVariable(localVariable); + frame.addLocalVariable(localVariable); + } + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index 96c7243a..2c79826c 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -22,10 +22,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.GenericLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.ObjectLocalVariable; -import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.CreateTypeFromTypeArgumentVisitor; -import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.RemoveLastContinueStatementVisitor; -import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; -import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchLocalVariableReferenceVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.*; import java.util.Collections; import java.util.Iterator; @@ -79,7 +76,7 @@ protected static Statement makeLoop( BaseExpression init = extractInit(statements, lineNumber); if (init != null) { - return new ClassFileForStatement(loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, null, null); + return newClassFileForStatement(localVariableMaker, loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, null, null); } } break; @@ -93,16 +90,19 @@ protected static Statement makeLoop( Expression subExpression = ((ExpressionStatement) subStatement).getExpression(); if (subExpression.getLineNumber() == lineNumber) { - return new ClassFileForStatement(loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, subExpression, null); + return newClassFileForStatement( + localVariableMaker, loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, subExpression, null); } else if (init != null) { - return new ClassFileForStatement(loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, null, subStatement); + return newClassFileForStatement( + localVariableMaker, loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, null, subStatement); } } else if (init != null) { - return new ClassFileForStatement(loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, null, subStatement); + return newClassFileForStatement( + localVariableMaker, loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, null, subStatement); } } else { // Unknown line numbers => Just try to find 'for (expression;;expression)' - return createForStatementWithoutLineNumber(loopBasicBlock, statements, condition, subStatements); + return createForStatementWithoutLineNumber(localVariableMaker, loopBasicBlock, statements, condition, subStatements); } break; default: @@ -119,11 +119,12 @@ protected static Statement makeLoop( BaseExpression init = extractInit(statements, lineNumber); if ((init != null) || (update.size() > 0)) { - return new ClassFileForStatement(loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, update, subStatements); + return newClassFileForStatement( + localVariableMaker, loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, condition, update, subStatements); } } else { // Unknown line numbers => Just try to find 'for (expression;;expression)' - return createForStatementWithoutLineNumber(loopBasicBlock, statements, condition, subStatements); + return createForStatementWithoutLineNumber(localVariableMaker, loopBasicBlock, statements, condition, subStatements); } break; } @@ -131,10 +132,10 @@ protected static Statement makeLoop( return new WhileStatement(condition, subStatements); } - public static Statement makeLoop(BasicBlock loopBasicBlock, Statements statements, Statements subStatements, Statements jumps) { + public static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Statements subStatements, Statements jumps) { subStatements.accept(REMOVE_LAST_CONTINUE_STATEMENT_VISITOR); - Statement loop = makeLoop(loopBasicBlock, statements, subStatements); + Statement loop = makeLoop(localVariableMaker, loopBasicBlock, statements, subStatements); int continueOffset = loopBasicBlock.getSub1().getFromOffset(); int breakOffset = loopBasicBlock.getNext().getFromOffset(); @@ -145,7 +146,7 @@ public static Statement makeLoop(BasicBlock loopBasicBlock, Statements statement return makeLabels(loopBasicBlock.getIndex(), continueOffset, breakOffset, loop, jumps); } - protected static Statement makeLoop(BasicBlock loopBasicBlock, Statements statements, Statements subStatements) { + protected static Statement makeLoop(LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, Statements statements, Statements subStatements) { int subStatementsSize = subStatements.size(); if ((subStatementsSize > 0) && (subStatements.getLast() == CONTINUE)) { @@ -168,7 +169,7 @@ protected static Statement makeLoop(BasicBlock loopBasicBlock, Statements statem BaseExpression init = extractInit(statements, lineNumber); if (init != null) { - return new ClassFileForStatement(loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, null, subExpression, null); + return newClassFileForStatement(localVariableMaker, loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, null, subExpression, null); } } } @@ -188,21 +189,22 @@ protected static Statement makeLoop(BasicBlock loopBasicBlock, Statements statem // Populates 'init' BaseExpression init = extractInit(statements, update.getFirst().getLineNumber()); - return new ClassFileForStatement(loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, null, update, subStatements); + return newClassFileForStatement(localVariableMaker, loopBasicBlock.getFromOffset(), loopBasicBlock.getToOffset(), init, null, update, subStatements); } } else { // Unknown line numbers => Just try to find 'for (expression;;expression)' - Statement statement = createForStatementWithoutLineNumber(loopBasicBlock, statements, BooleanExpression.TRUE, subStatements); + Statement statement = createForStatementWithoutLineNumber(localVariableMaker, loopBasicBlock, statements, BooleanExpression.TRUE, subStatements); - if (statement != null) + if (statement != null) { return statement; + } } } return new WhileStatement(BooleanExpression.TRUE, subStatements); } - public static Statement makeDoWhileLoop(BasicBlock loopBasicBlock, BasicBlock lastSubBasicBlock, Expression condition, Statements subStatements, Statements jumps) { + public static Statement makeDoWhileLoop(BasicBlock loopBasicBlock, Expression condition, Statements subStatements, Statements jumps) { subStatements.accept(REMOVE_LAST_CONTINUE_STATEMENT_VISITOR); Statement loop = new DoWhileStatement(condition, subStatements); @@ -300,7 +302,9 @@ protected static Expressions extractUpdate(Statements statements, int firstLineN return update; } - protected static Statement createForStatementWithoutLineNumber(BasicBlock basicBlock, Statements statements, Expression condition, Statements subStatements) { + protected static Statement createForStatementWithoutLineNumber( + LocalVariableMaker localVariableMaker, BasicBlock basicBlock, Statements statements, Expression condition, Statements subStatements) { + if (!statements.isEmpty()) { Statement statement = statements.getLast(); @@ -332,7 +336,8 @@ protected static Statement createForStatementWithoutLineNumber(BasicBlock basicB return new WhileStatement(condition, subStatements); } - if ((expression.getClass() == ClassFileLocalVariableReferenceExpression.class) && (((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable() == localVariable)) { + if ((expression.getClass() == ClassFileLocalVariableReferenceExpression.class) && + (((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable() == localVariable)) { statements.removeLast(); subStatements.removeLast(); @@ -340,7 +345,8 @@ protected static Statement createForStatementWithoutLineNumber(BasicBlock basicB condition = null; } - return new ClassFileForStatement(basicBlock.getFromOffset(), basicBlock.getToOffset(), init, condition, update, subStatements); + return newClassFileForStatement( + localVariableMaker, basicBlock.getFromOffset(), basicBlock.getToOffset(), init, condition, update, subStatements); } } } @@ -412,13 +418,16 @@ protected static Statement makeForEachArray( boe = (BinaryOperatorExpression)expression; - if ((boe.getRightExpression().getClass() != ArrayExpression.class) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getLineNumber() != condition.getLineNumber())) { + if ((boe.getRightExpression().getClass() != ArrayExpression.class) || + (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || + (boe.getLineNumber() != condition.getLineNumber())) { return null; } ArrayExpression arrayExpression = (ArrayExpression)boe.getRightExpression(); - if ((arrayExpression.getExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (arrayExpression.getIndex().getClass() != ClassFileLocalVariableReferenceExpression.class)) { + if ((arrayExpression.getExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || + (arrayExpression.getIndex().getClass() != ClassFileLocalVariableReferenceExpression.class)) { return null; } if (((ClassFileLocalVariableReferenceExpression)arrayExpression.getExpression()).getLocalVariable() != syntheticArray) { @@ -472,10 +481,13 @@ protected static Statement makeForEachArray( boe = (BinaryOperatorExpression)expression; - if ((boe.getLineNumber() != lineNumber) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getRightExpression().getClass() != IntegerConstantExpression.class)) { + if ((boe.getLineNumber() != lineNumber) || + (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || + (boe.getRightExpression().getClass() != IntegerConstantExpression.class)) { return null; } - if ((((IntegerConstantExpression)boe.getRightExpression()).getValue() != 0) || (((ClassFileLocalVariableReferenceExpression)boe.getLeftExpression()).getLocalVariable() != syntheticIndex)) { + if ((((IntegerConstantExpression)boe.getRightExpression()).getValue() != 0) || + (((ClassFileLocalVariableReferenceExpression)boe.getLeftExpression()).getLocalVariable() != syntheticIndex)) { return null; } @@ -486,10 +498,12 @@ protected static Statement makeForEachArray( boe = (BinaryOperatorExpression)condition; - if ((boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getRightExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { + if ((boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || + (boe.getRightExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { return null; } - if ((((ClassFileLocalVariableReferenceExpression)boe.getLeftExpression()).getLocalVariable() != syntheticIndex) || (((ClassFileLocalVariableReferenceExpression)boe.getRightExpression()).getLocalVariable() != syntheticLength)) { + if ((((ClassFileLocalVariableReferenceExpression)boe.getLeftExpression()).getLocalVariable() != syntheticIndex) || + (((ClassFileLocalVariableReferenceExpression)boe.getRightExpression()).getLocalVariable() != syntheticLength)) { return null; } @@ -550,7 +564,8 @@ protected static Statement makeForEachList( MethodInvocationExpression mie = (MethodInvocationExpression)condition; - if (!mie.getName().equals("hasNext") || !mie.getInternalTypeName().equals("java/util/Iterator") || (mie.getExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { + if (!mie.getName().equals("hasNext") || !mie.getInternalTypeName().equals("java/util/Iterator") || + (mie.getExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { return null; } @@ -575,7 +590,10 @@ protected static Statement makeForEachList( BinaryOperatorExpression boe = (BinaryOperatorExpression)es.getExpression(); - if ((boe == null) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || (boe.getRightExpression().getClass() != ClassFileMethodInvocationExpression.class) || (boe.getLineNumber() != condition.getLineNumber())) { + if ((boe == null) || + (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class) || + (boe.getRightExpression().getClass() != ClassFileMethodInvocationExpression.class) || + (boe.getLineNumber() != condition.getLineNumber())) { return null; } @@ -624,7 +642,9 @@ protected static Statement makeForEachList( mie = (MethodInvocationExpression)expression; - if (!mie.getName().equals("next") || !mie.getInternalTypeName().equals("java/util/Iterator") || (mie.getExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { + if (!mie.getName().equals("next") || + !mie.getInternalTypeName().equals("java/util/Iterator") || + (mie.getExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { return null; } if (((ClassFileLocalVariableReferenceExpression)mie.getExpression()).getLocalVariable() != syntheticIterator) { @@ -727,4 +747,19 @@ protected static Statement makeLabels(int loopIndex, int continueOffset, int bre return loop; } + + protected static ClassFileForStatement newClassFileForStatement( + LocalVariableMaker localVariableMaker, int fromOffset, int toOffset, BaseExpression init, + Expression condition, BaseExpression update, BaseStatement statements) { + ChangeFrameOfLocalVariablesVisitor visitor = new ChangeFrameOfLocalVariablesVisitor(localVariableMaker); + + if (condition != null) { + condition.accept(visitor); + } + if (update != null) { + update.accept(visitor); + } + + return new ClassFileForStatement(fromOffset, toOffset, init, condition, update, statements); + } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 5d0fb1d3..a40a98b3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -641,7 +641,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st makeStatements(watchdog, ifBB.getCondition(), subStatements, jumps); replacePreOperatorWithPostOperator(subStatements); - statements.add(LoopStatementMaker.makeDoWhileLoop(basicBlock, ifBB, stack.pop(), subStatements, jumps)); + statements.add(LoopStatementMaker.makeDoWhileLoop(basicBlock, stack.pop(), subStatements, jumps)); } else { // 'while' or 'for' loop ifBB.getCondition().inverseCondition(); @@ -684,10 +684,11 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st } makeStatements(watchdog, last.getCondition(), subStatements, jumps); - statements.add(LoopStatementMaker.makeDoWhileLoop(basicBlock, last, stack.pop(), subStatements, jumps)); + statements.add(LoopStatementMaker.makeDoWhileLoop(basicBlock, stack.pop(), subStatements, jumps)); } else { // Infinite loop - statements.add(LoopStatementMaker.makeLoop(basicBlock, statements, makeSubStatements(watchdog, sub1, statements, jumps, updateBasicBlock), jumps)); + statements.add(LoopStatementMaker.makeLoop( + localVariableMaker, basicBlock, statements, makeSubStatements(watchdog, sub1, statements, jumps, updateBasicBlock), jumps)); } makeStatements(watchdog, basicBlock.getNext(), statements, jumps); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/ChangeFrameOfLocalVariablesVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/ChangeFrameOfLocalVariablesVisitor.java new file mode 100644 index 00000000..243bb93f --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/ChangeFrameOfLocalVariablesVisitor.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.reference.InnerObjectReference; +import org.jd.core.v1.model.javasyntax.reference.ObjectReference; +import org.jd.core.v1.model.javasyntax.statement.*; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.LocalVariableMaker; + +public class ChangeFrameOfLocalVariablesVisitor extends AbstractJavaSyntaxVisitor { + protected LocalVariableMaker localVariableMaker; + + public ChangeFrameOfLocalVariablesVisitor(LocalVariableMaker localVariableMaker) { + this.localVariableMaker = localVariableMaker; + } + + @Override + public void visit(LocalVariableReferenceExpression expression) { + localVariableMaker.changeFrame(((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable()); + } + + @Override public void visit(FloatConstantExpression expression) {} + @Override public void visit(IntegerConstantExpression expression) {} + @Override public void visit(ConstructorReferenceExpression expression) {} + @Override public void visit(DoubleConstantExpression expression) {} + @Override public void visit(EnumConstantReferenceExpression expression) {} + @Override public void visit(LongConstantExpression expression) {} + @Override public void visit(BreakStatement statement) {} + @Override public void visit(ByteCodeStatement statement) {} + @Override public void visit(ContinueStatement statement) {} + @Override public void visit(NullExpression expression) {} + @Override public void visit(ObjectTypeReferenceExpression expression) {} + @Override public void visit(SuperExpression expression) {} + @Override public void visit(ThisExpression expression) {} + @Override public void visit(TypeReferenceDotClassExpression expression) {} + @Override public void visit(ObjectReference reference) {} + @Override public void visit(InnerObjectReference reference) {} + @Override public void visit(TypeArguments type) {} + @Override public void visit(WildcardExtendsTypeArgument type) {} + @Override public void visit(ObjectType type) {} + @Override public void visit(InnerObjectType type) {} + @Override public void visit(WildcardSuperTypeArgument type) {} + @Override public void visit(Types types) {} + @Override public void visit(TypeParameterWithTypeBounds type) {} +} From 8fee8755f035d111d15bb9649cecc4942e714bcd Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 30 Dec 2019 23:37:08 +0100 Subject: [PATCH 144/211] Fix syntax errors in decompiled sources --- .../visitor/UpdateIntegerConstantTypeVisitor.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java index ce884ef0..ea43c91d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/UpdateIntegerConstantTypeVisitor.java @@ -317,9 +317,12 @@ protected BaseExpression updateExpressions(BaseType types, BaseExpression expres switch (((PrimitiveType)type).getJavaPrimitiveFlags()) { case FLAG_BYTE: case FLAG_SHORT: - e.set(i, new CastExpression(type, updatedParameter)); + updatedParameter = new CastExpression(type, updatedParameter); + break; } } + + e.set(i, updatedParameter); } } } else { @@ -332,10 +335,12 @@ protected BaseExpression updateExpressions(BaseType types, BaseExpression expres switch (((PrimitiveType)type).getJavaPrimitiveFlags()) { case FLAG_BYTE: case FLAG_SHORT: - expressions = new CastExpression(type, updatedParameter); + updatedParameter = new CastExpression(type, updatedParameter); break; } } + + expressions = updatedParameter; } } From 181341e4e8bbadb3c400e0ede816f143040aa696 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 31 Dec 2019 10:54:39 +0100 Subject: [PATCH 145/211] Fix syntax errors in decompiled sources --- .../util/JavaFragmentFactory.java | 37 +++++++++++-------- .../visitor/ExpressionVisitor.java | 8 +++- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java index dd64a568..e509b9b1 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java @@ -15,7 +15,7 @@ public class JavaFragmentFactory { public static void addSpacerAfterPackage(List fragments) { fragments.add(new SpacerFragment(0, 1, 1, 0, "Spacer after package")); - fragments.add(new SpacerFragment(0, 1, 1, 1, "Second lastSpacer after package")); + fragments.add(new SpacerFragment(0, 1, 1, 1, "Second spacer after package")); } public static void addSpacerAfterImports(List fragments) { @@ -28,7 +28,7 @@ public static void addSpacerBeforeMainDeclaration(List fragments) { public static void addEndArrayInitializerInParameter(List fragments, StartBlockFragment start) { fragments.add(new EndBlockInParameterFragment(0, 0, 1, 20, "End array initializer", start)); - fragments.add(new SpaceSpacerFragment(0, 0, Integer.MAX_VALUE, 21, "End array initializer lastSpacer in parameter")); + fragments.add(new SpaceSpacerFragment(0, 0, Integer.MAX_VALUE, 21, "End array initializer spacer in parameter")); } public static void addEndArrayInitializer(List fragments, StartBlockFragment start) { @@ -49,7 +49,7 @@ public static void addEndTypeBody(List fragments, StartBodyFragment st public static void addEndSubTypeBodyInParameter(List fragments, StartBodyFragment start) { fragments.add(new EndBodyInParameterFragment(0, 1, 1, 10, "End sub type body in parameter", start)); - fragments.add(new SpaceSpacerFragment(0, 0, Integer.MAX_VALUE, 13, "End sub type body lastSpacer in parameter")); + fragments.add(new SpaceSpacerFragment(0, 0, Integer.MAX_VALUE, 13, "End sub type body spacer in parameter")); } public static void addEndSubTypeBody(List fragments, StartBodyFragment start) { @@ -57,13 +57,13 @@ public static void addEndSubTypeBody(List fragments, StartBodyFragment } public static void addEndSingleStatementBlock(List fragments, StartSingleStatementBlockFragment start) { - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "End single statement block lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "End single statement block spacer")); //fragments.add(new EndSingleStatementBlockFragment(0, 1, 2, 15, "End single statement block", start)); fragments.add(new EndSingleStatementBlockFragment(0, 0, 1, 6, "End single statement block", start)); } public static void addEndStatementsBlock(List fragments, StartStatementsBlockFragment.Group group) { - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "End statement block lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "End statement block spacer")); fragments.add(new EndStatementsBlockFragment(0, 1, 2, 15, "End statement block", group)); } @@ -71,9 +71,14 @@ public static void addSpacerAfterEndStatementsBlock(List fragments) { fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 11, "Spacer after end statement block")); } + public static void addEndStatementsInLambdaBlockInParameter(List fragments, StartBlockFragment start) { + fragments.add(new EndBlockInParameterFragment(0, 1, 2, 15, "End statements in lambda block spacer in parameter", start)); + fragments.add(new SpaceSpacerFragment(0, 0, Integer.MAX_VALUE, 15, "End statements in lambda block spacer in parameter")); + } + public static void addEndStatementsInLambdaBlock(List fragments, StartBlockFragment start) { - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 15, "End statements in lambda block lastSpacer")); - fragments.add(new EndBlockFragment(0, 1, 2, 15, "End statements in lambda block lastSpacer", start)); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 15, "End statements in lambda block spacer")); + fragments.add(new EndBlockFragment(0, 1, 2, 15, "End statements in lambda block spacer", start)); } public static void addSpacerAfterMemberAnnotations(List fragments) { @@ -100,7 +105,7 @@ public static void addSpacerBeforeImplements(List fragments) { public static void addSpacerBetweenEnumValues(List fragments, int preferredLineCount) { fragments.add(TokensFragment.COMMA); fragments.add(new SpaceSpacerFragment(0, preferredLineCount, 1, 10, "Spacer between enum values")); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 24, "Second lastSpacer between enum values")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 24, "Second spacer between enum values")); } public static void addSpacerBetweenFieldDeclarators(List fragments) { @@ -159,49 +164,49 @@ public static StartBodyFragment addStartMethodBody(List fragments) { public static StartBodyFragment addStartTypeBody(List fragments) { StartBodyFragment fragment = new StartBodyFragment(0, 1, 2, 4, "Start type body"); fragments.add(fragment); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 13, "Start type body lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 13, "Start type body spacer")); return fragment; } public static StartSingleStatementBlockFragment addStartSingleStatementBlock(List fragments) { StartSingleStatementBlockFragment fragment = new StartSingleStatementBlockFragment(0, 1, 2, 18, "Start single statement block"); fragments.add(fragment); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 23, "Start single statement block lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 23, "Start single statement block spacer")); return fragment; } public static StartStatementsBlockFragment.Group addStartStatementsBlock(List fragments) { StartStatementsBlockFragment fragment = new StartStatementsBlockFragment(0, 1, 2, 14, "Start statements block"); fragments.add(fragment); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "Start statements block lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "Start statements block spacer")); return fragment.getGroup(); } public static StartBlockFragment addStartStatementsInLambdaBlock(List fragments) { StartBlockFragment fragment = new StartBlockFragment(0, 1, 2, 14, "Start statements in lambda block"); fragments.add(fragment); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 14, "Start statements in lambda block lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 14, "Start statements in lambda block spacer")); return fragment; } public static StartStatementsBlockFragment.Group addStartStatementsDoWhileBlock(List fragments) { StartStatementsDoWhileBlockFragment fragment = new StartStatementsDoWhileBlockFragment(0, 1, 2, 14, "Start statements do-while block"); fragments.add(fragment); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 14, "Start statements do-while block lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 14, "Start statements do-while block spacer")); return fragment.getGroup(); } public static StartStatementsBlockFragment.Group addStartStatementsTryBlock(List fragments) { StartStatementsTryBlockFragment fragment = new StartStatementsTryBlockFragment(0, 1, 2, 14, "Start statements try block"); fragments.add(fragment); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 14, "Start statements try block lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 14, "Start statements try block spacer")); return fragment.getGroup(); } public static void addStartStatementsBlock(List fragments, StartStatementsBlockFragment.Group group) { - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 23, "Start statements block pre lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 23, "Start statements block pre spacer")); fragments.add(new StartStatementsBlockFragment(0, 1, 2, 14, "Start statements block", group)); - fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "Start statements block post lastSpacer")); + fragments.add(new SpacerFragment(0, 0, Integer.MAX_VALUE, 19, "Start statements block post spacer")); } public static ImportsFragment newImportsFragment() { diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index 6000bbc4..9b36b326 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -173,7 +173,7 @@ public void visit(Expressions list) { boolean ief = inExpressionFlag; Iterator iterator = list.iterator(); - for (int i=size-1; i>0; i--) { + while (size-- > 1) { inExpressionFlag = true; iterator.next().accept(this); @@ -328,7 +328,11 @@ protected void visitLambdaBody(BaseStatement statementList) { tokens = new Tokens(); statementList.accept(this); - JavaFragmentFactory.addEndStatementsInLambdaBlock(fragments, start); + if (inExpressionFlag) { + JavaFragmentFactory.addEndStatementsInLambdaBlockInParameter(fragments, start); + } else { + JavaFragmentFactory.addEndStatementsInLambdaBlock(fragments, start); + } tokens = new Tokens(); } From 7b692b723df9f038593b72cb0c468af256a7bcd4 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Tue, 31 Dec 2019 12:40:11 +0100 Subject: [PATCH 146/211] Fix syntax errors in decompiled sources --- .../util/TryWithResourcesStatementMaker.java | 152 ++++++++++++------ 1 file changed, 105 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java index 9d5be7d9..b3f9db2e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TryWithResourcesStatementMaker.java @@ -23,34 +23,28 @@ public class TryWithResourcesStatementMaker { - public static Statement make(LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, DefaultList catchClauses, Statements finallyStatements) { + public static Statement make( + LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, + DefaultList catchClauses, Statements finallyStatements) { int size = statements.size(); if ((size < 2) || (finallyStatements == null) || (finallyStatements.size() != 1) || !checkThrowable(catchClauses)) { return null; } - Statement statement = finallyStatements.getFirst(); - - if (statement.getClass() != IfStatement.class) { - return null; - } - - IfStatement is = (IfStatement)statement; - - statement = statements.get(size-2); + Statement statement = statements.get(size - 2); if (statement.getClass() != ExpressionStatement.class) { return null; } - Expression expression = ((ExpressionStatement)statement).getExpression(); + Expression expression = ((ExpressionStatement) statement).getExpression(); if (expression.getClass() != BinaryOperatorExpression.class) { return null; } - BinaryOperatorExpression boe = (BinaryOperatorExpression)expression; + BinaryOperatorExpression boe = (BinaryOperatorExpression) expression; expression = boe.getLeftExpression(); @@ -58,47 +52,68 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements s return null; } - AbstractLocalVariable lv1 = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + AbstractLocalVariable lv1 = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); - statement = statements.get(size-1); + statement = statements.get(size - 1); if (statement.getClass() != ExpressionStatement.class) { return null; } - expression = ((ExpressionStatement)statement).getExpression(); + expression = ((ExpressionStatement) statement).getExpression(); if (expression.getClass() != BinaryOperatorExpression.class) { return null; } - expression = ((BinaryOperatorExpression)expression).getLeftExpression(); + expression = ((BinaryOperatorExpression) expression).getLeftExpression(); if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { return null; } - AbstractLocalVariable lv2 = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + AbstractLocalVariable lv2 = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); - statement = is.getStatements().getFirst(); + statement = finallyStatements.getFirst(); - if (statement.getClass() != IfElseStatement.class) { - return null; + if (statement.getClass() == IfStatement.class) { + IfStatement is = (IfStatement) statement; + + if (lv1 == getLocalVariable(is.getCondition())) { + statement = is.getStatements().getFirst(); + + if (statement.getClass() == IfElseStatement.class) { + return parsePatternAddSuppressed(localVariableMaker, statements, tryStatements, finallyStatements, boe, lv1, lv2, statement); + } + if (statement.getClass() == ExpressionStatement.class) { + return parsePatternCloseResource(localVariableMaker, statements, tryStatements, finallyStatements, boe, lv1, lv2, statement); + } + } + } + + if (statement.getClass() == ExpressionStatement.class) { + return parsePatternCloseResource(localVariableMaker, statements, tryStatements, finallyStatements, boe, lv1, lv2, statement); } - IfElseStatement ies = (IfElseStatement)statement; + return null; + } - if (lv1 != getLocalVariable(is.getCondition())) { + protected static Statement parsePatternAddSuppressed( + LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, Statements finallyStatements, + BinaryOperatorExpression boe, AbstractLocalVariable lv1, AbstractLocalVariable lv2, Statement statement) { + if (statement.getClass() != IfElseStatement.class) { return null; } + IfElseStatement ies = (IfElseStatement) statement; + statement = ies.getStatements().getFirst(); if (statement.getClass() != ClassFileTryStatement.class) { return null; } - ClassFileTryStatement ts = (ClassFileTryStatement)statement; + ClassFileTryStatement ts = (ClassFileTryStatement) statement; statement = ies.getElseStatements().getFirst(); @@ -106,16 +121,16 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements s return null; } - expression = ((ExpressionStatement)statement).getExpression(); + Expression expression = ((ExpressionStatement) statement).getExpression(); if (expression.getClass() != ClassFileMethodInvocationExpression.class) { return null; } - MethodInvocationExpression mie = (MethodInvocationExpression)expression; + MethodInvocationExpression mie = (MethodInvocationExpression) expression; - if ((is.getCondition().getLineNumber() != mie.getLineNumber()) || (ts.getFinallyStatements() != null) || - (lv2 != getLocalVariable(ies.getCondition())) || !checkThrowable(ts.getCatchClauses()) || !checkCloseInvocation(mie, lv1)) { + if ((ts.getFinallyStatements() != null) || (lv2 != getLocalVariable(ies.getCondition())) || + !checkThrowable(ts.getCatchClauses()) || !checkCloseInvocation(mie, lv1)) { return null; } @@ -125,13 +140,13 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements s return null; } - expression = ((ExpressionStatement)statement).getExpression(); + expression = ((ExpressionStatement) statement).getExpression(); if (expression.getClass() != ClassFileMethodInvocationExpression.class) { return null; } - mie = (MethodInvocationExpression)expression; + mie = (MethodInvocationExpression) expression; if (!checkCloseInvocation(mie, lv1)) { return null; @@ -143,13 +158,13 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements s return null; } - expression = ((ExpressionStatement)statement).getExpression(); + expression = ((ExpressionStatement) statement).getExpression(); if (expression.getClass() != ClassFileMethodInvocationExpression.class) { return null; } - mie = (MethodInvocationExpression)expression; + mie = (MethodInvocationExpression) expression; if (!mie.getName().equals("addSuppressed") || !mie.getDescriptor().equals("(Ljava/lang/Throwable;)V")) { return null; @@ -160,23 +175,11 @@ public static Statement make(LocalVariableMaker localVariableMaker, Statements s if (expression.getClass() != ClassFileLocalVariableReferenceExpression.class) { return null; } - - if (((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable() != lv2) { + if (((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable() != lv2) { return null; } - // Remove resource & synthetic local variables - statements.removeLast(); - statements.removeLast(); - lv1.setDeclared(true); - localVariableMaker.removeLocalVariable(lv2); - - // Create try-with-resources statement - DefaultList resources = new DefaultList<>(); - - resources.add(new TryStatement.Resource((ObjectType)lv1.getType(), lv1.getName(), boe.getRightExpression())); - - return new ClassFileTryStatement(resources, tryStatements, null, finallyStatements, false, false); + return newTryStatement(localVariableMaker, statements, tryStatements, finallyStatements, boe, lv1, lv2); } protected static boolean checkThrowable(List catchClauses) { @@ -188,7 +191,7 @@ protected static AbstractLocalVariable getLocalVariable(Expression condition) { return null; } - BinaryOperatorExpression boe = (BinaryOperatorExpression)condition; + BinaryOperatorExpression boe = (BinaryOperatorExpression) condition; if (!boe.getOperator().equals("!=") || (boe.getRightExpression().getClass() != NullExpression.class) || (boe.getLeftExpression().getClass() != ClassFileLocalVariableReferenceExpression.class)) { return null; @@ -202,10 +205,65 @@ protected static boolean checkCloseInvocation(MethodInvocationExpression mie, Ab Expression expression = mie.getExpression(); if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { - return ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable() == lv; + return ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable() == lv; } } return false; } + + protected static Statement parsePatternCloseResource( + LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, Statements finallyStatements, + BinaryOperatorExpression boe, AbstractLocalVariable lv1, AbstractLocalVariable lv2, Statement statement) { + Expression expression = ((ExpressionStatement) statement).getExpression(); + + if (expression.getClass() != ClassFileMethodInvocationExpression.class) { + return null; + } + + MethodInvocationExpression mie = (MethodInvocationExpression) expression; + + if (!mie.getName().equals("$closeResource") || !mie.getDescriptor().equals("(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V")) { + return null; + } + + DefaultList parameters = mie.getParameters().getList(); + Expression parameter0 = parameters.get(0); + + if (parameter0.getClass() != ClassFileLocalVariableReferenceExpression.class) { + return null; + } + if (((ClassFileLocalVariableReferenceExpression)parameter0).getLocalVariable() != lv2) { + return null; + } + + Expression parameter1 = parameters.get(1); + + if (parameter1.getClass() != ClassFileLocalVariableReferenceExpression.class) { + return null; + } + if (((ClassFileLocalVariableReferenceExpression)parameter1).getLocalVariable() != lv1) { + return null; + } + + return newTryStatement(localVariableMaker, statements, tryStatements, finallyStatements, boe, lv1, lv2); + } + + protected static ClassFileTryStatement newTryStatement( + LocalVariableMaker localVariableMaker, Statements statements, Statements tryStatements, Statements finallyStatements, + BinaryOperatorExpression boe, AbstractLocalVariable lv1, AbstractLocalVariable lv2) { + + // Remove resource & synthetic local variables + statements.removeLast(); + statements.removeLast(); + lv1.setDeclared(true); + localVariableMaker.removeLocalVariable(lv2); + + // Create try-with-resources statement + DefaultList resources = new DefaultList<>(); + + resources.add(new TryStatement.Resource((ObjectType) lv1.getType(), lv1.getName(), boe.getRightExpression())); + + return new ClassFileTryStatement(resources, tryStatements, null, finallyStatements, false, false); + } } From 2e3bf63d2e09c6f3ae005afd1d00805eca14ebc5 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 5 Jan 2020 20:03:31 +0100 Subject: [PATCH 147/211] Fix syntax errors in decompiled sources --- .../util/LoopStatementMaker.java | 30 ++++---- .../TypeParametersToTypeArgumentsBinder.java | 4 +- .../visitor/AddCastExpressionVisitor.java | 68 +++++++++++-------- .../visitor/ExpressionVisitor.java | 3 + .../jd/core/v1/JarFileToJavaSourceTest.java | 24 ++++++- 5 files changed, 79 insertions(+), 50 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index 2c79826c..2a2dbb78 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -9,13 +9,11 @@ import org.jd.core.v1.model.javasyntax.expression.*; import org.jd.core.v1.model.javasyntax.statement.*; -import org.jd.core.v1.model.javasyntax.type.BaseType; -import org.jd.core.v1.model.javasyntax.type.GenericType; -import org.jd.core.v1.model.javasyntax.type.ObjectType; -import org.jd.core.v1.model.javasyntax.type.Type; +import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.BasicBlock; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileMethodInvocationExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileNewExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileBreakContinueStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForEachStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; @@ -31,6 +29,7 @@ import static org.jd.core.v1.model.javasyntax.statement.ContinueStatement.CONTINUE; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_ITERABLE; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; public class LoopStatementMaker { protected static final RemoveLastContinueStatementVisitor REMOVE_LAST_CONTINUE_STATEMENT_VISITOR = new RemoveLastContinueStatementVisitor(); @@ -571,10 +570,6 @@ protected static Statement makeForEachList( AbstractLocalVariable syntheticIterator = ((ClassFileLocalVariableReferenceExpression)mie.getExpression()).getLocalVariable(); - if ((syntheticIterator.getName() != null) && (syntheticIterator.getName().indexOf('$') == -1)) { - return null; - } - // Iterator i$ = list.iterator(); Statement lastStatement = statements.getLast(); @@ -670,7 +665,11 @@ protected static Statement makeForEachList( statements.removeLast(); subStatements.remove(0); item.setDeclared(true); - localVariableMaker.removeLocalVariable(syntheticIterator); + + if (syntheticIterator.getReferences().size() == 3) { + // If local variable is used only for this loop + localVariableMaker.removeLocalVariable(syntheticIterator); + } Type type = list.getType(); @@ -678,11 +677,12 @@ protected static Statement makeForEachList( ObjectType listType = (ObjectType)type; if (listType.getTypeArguments() == null) { - if (item.getType().isObject()) { - ObjectType ot = (ObjectType) item.getType(); - - if (ot.getTypeArguments() != null) { - list = new CastExpression(TYPE_ITERABLE.createType(ot), list); + if (!TYPE_OBJECT.equals(item.getType())) { + if (list.getClass() == ClassFileNewExpression.class) { + ClassFileNewExpression ne = (ClassFileNewExpression)list; + ne.setType(listType.createType(DiamondTypeArgument.DIAMOND)); + } else { + list = new CastExpression(TYPE_ITERABLE.createType(item.getType()), list); } } } else { @@ -691,7 +691,7 @@ protected static Statement makeForEachList( type = visitor2.getType(); if (type != null) { - if (ObjectType.TYPE_OBJECT.equals(item.getType())) { + if (TYPE_OBJECT.equals(item.getType())) { ((ObjectLocalVariable) item).setType(typeBounds, type); } else if (item.getType().isGeneric()) { ((GenericLocalVariable) item).setType((GenericType) type); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 573a2a2a..430bd5d0 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -165,7 +165,7 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { Expression expression = mie.getExpression(); Type expressionType = expression.getType(); - if (staticMethod || (mie.getTypeParameters() != null) || expressionType.isGeneric() || (expression.getClass() != ThisExpression.class)) { + if (staticMethod || (mie.getTypeParameters() != null) || !mie.getInternalTypeName().equals(internalTypeName)) { TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(mie.getInternalTypeName()); if (typeTypes != null) { @@ -495,7 +495,7 @@ protected Type getExpressionType(ClassFileMethodInvocationExpression mie) { return null; } - if (staticMethod || (mie.getExpression().getClass() != ThisExpression.class)) { + if (staticMethod || !mie.getInternalTypeName().equals(internalTypeName)) { TypeMaker.TypeTypes typeTypes = typeMaker.makeTypeTypes(mie.getInternalTypeName()); if ((typeTypes != null) && (typeTypes.typeParameters != null)) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index 4b4a8b11..9e972d1a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -24,6 +24,8 @@ import java.util.Map; +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_BRIDGE; +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_SYNTHETIC; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; public class AddCastExpressionVisitor extends AbstractJavaSyntaxVisitor { @@ -54,11 +56,13 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(FieldDeclaration declaration) { - Type t = type; + if ((declaration.getFlags() & FLAG_SYNTHETIC) == 0) { + Type t = type; - type = declaration.getType(); - declaration.getFieldDeclarators().accept(this); - type = t; + type = declaration.getType(); + declaration.getFieldDeclarators().accept(this); + type = t; + } } @Override @@ -96,36 +100,40 @@ public void visit(StaticInitializerDeclaration declaration) { @Override public void visit(ConstructorDeclaration declaration) { - BaseStatement statements = declaration.getStatements(); - - if (statements != null) { - Map tb = typeBounds; - BaseType et = exceptionTypes; - - typeBounds = ((ClassFileConstructorDeclaration)declaration).getTypeBounds(); - exceptionTypes = declaration.getExceptionTypes(); - statements.accept(this); - typeBounds = tb; - exceptionTypes = et; + if ((declaration.getFlags() & (FLAG_SYNTHETIC|FLAG_BRIDGE)) == 0) { + BaseStatement statements = declaration.getStatements(); + + if (statements != null) { + Map tb = typeBounds; + BaseType et = exceptionTypes; + + typeBounds = ((ClassFileConstructorDeclaration) declaration).getTypeBounds(); + exceptionTypes = declaration.getExceptionTypes(); + statements.accept(this); + typeBounds = tb; + exceptionTypes = et; + } } } @Override public void visit(MethodDeclaration declaration) { - BaseStatement statements = declaration.getStatements(); - - if (statements != null) { - Map tb = typeBounds; - Type rt = returnedType; - BaseType et = exceptionTypes; - - typeBounds = ((ClassFileMethodDeclaration)declaration).getTypeBounds(); - returnedType = declaration.getReturnedType(); - exceptionTypes = declaration.getExceptionTypes(); - statements.accept(this); - typeBounds = tb; - returnedType = rt; - exceptionTypes = et; + if ((declaration.getFlags() & (FLAG_SYNTHETIC|FLAG_BRIDGE)) == 0) { + BaseStatement statements = declaration.getStatements(); + + if (statements != null) { + Map tb = typeBounds; + Type rt = returnedType; + BaseType et = exceptionTypes; + + typeBounds = ((ClassFileMethodDeclaration) declaration).getTypeBounds(); + returnedType = declaration.getReturnedType(); + exceptionTypes = declaration.getExceptionTypes(); + statements.accept(this); + typeBounds = tb; + returnedType = rt; + exceptionTypes = et; + } } } @@ -136,7 +144,7 @@ public void visit(LambdaIdentifiersExpression expression) { if (statements != null) { Type rt = returnedType; - returnedType = expression.getReturnedType(); + returnedType = ObjectType.TYPE_OBJECT; statements.accept(this); returnedType = rt; } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index 9b36b326..54daa49a 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -395,7 +395,10 @@ public void visit(MethodInvocationExpression expression) { tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); if (parameters != null) { + boolean ief = inExpressionFlag; + inExpressionFlag = false; parameters.accept(this); + inExpressionFlag = ief; } tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 7739025d..60c4a6fa 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -54,11 +54,29 @@ public void testCommonsLang3() throws Exception { test(org.apache.commons.lang3.JavaVersion.class); } + @Test + public void testJavaPoet() throws Exception { + // Decompile and recompile 'com.squareup:javapoet:1.11.1' + test(com.squareup.javapoet.JavaFile.class); + } + + @Test + public void testJSoup() throws Exception { + // Decompile and recompile 'org.jsoup:jsoup:1.12.1' + test(org.jsoup.Jsoup.class); + } + + @Test + public void testJUnit4() throws Exception { + // Decompile and recompile 'junit:junit:4.12' + test(org.junit.Test.class); + } + // TODO In progress // @Test -// public void testJUnit4() throws Exception { -// // Decompile and recompile 'junit:junit:4.12' -// test(org.junit.Test.class); +// public void testLog4j() throws Exception { +// // Decompile and recompile 'log4j:log4j:1.2.17' +// test(org.apache.log4j.Category.class); // } protected void test(Class clazz) throws Exception { From 893af8e11ec9f6d930862398b394c9b192990cb4 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 5 Jan 2020 23:46:16 +0100 Subject: [PATCH 148/211] Fix syntax errors in decompiled sources --- .../util/TypeParametersToTypeArgumentsBinder.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 430bd5d0..306229cc 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -195,6 +195,9 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { ObjectType objectType = (ObjectType) type; ObjectType mieTypeObjectType = (ObjectType) t; t = typeMaker.searchSuperParameterizedType(objectType, mieTypeObjectType); + if (t == null) { + t = mie.getType(); + } } Map bindings = createBindings(expression, typeParameters, typeArguments, methodTypeParameters, type, t, parameterTypes, parameters); @@ -276,6 +279,9 @@ protected void bind(Type type, ClassFileNewExpression ne) { if (type.isObject()) { ObjectType objectType = (ObjectType)type; t = typeMaker.searchSuperParameterizedType(objectType, neObjectType); + if (t == null) { + t = neObjectType; + } } Map bindings = createBindings(null, typeParameters, typeArguments, null, type, t, parameterTypes, parameters); From fe8cab73bee82c99ed3927923571548df1de78be Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 8 Jan 2020 20:15:16 +0100 Subject: [PATCH 149/211] Fix syntax errors in decompiled sources --- .../declaration/FieldDeclaration.java | 8 + .../ClassFileFieldDeclaration.java | 8 - .../util/ByteCodeParser.java | 147 ++++++++++++++---- .../util/LoopStatementMaker.java | 29 ++-- .../util/StatementMaker.java | 4 +- .../TypeParametersToTypeArgumentsBinder.java | 16 +- .../BaseTypeToErasedTypeArgumentVisitor.java | 38 ----- .../visitor/EraseTypeArgumentVisitor.java | 71 +++++++++ .../visitor/InitInnerClassVisitor.java | 30 +++- .../visitor/ExpressionVisitor.java | 4 +- .../visitor/TypeVisitor.java | 22 +-- 11 files changed, 257 insertions(+), 120 deletions(-) delete mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/EraseTypeArgumentVisitor.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java index 04ccf1fa..c1c24571 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/FieldDeclaration.java @@ -35,6 +35,10 @@ public int getFlags() { return flags; } + public void setFlags(int flags) { + this.flags = flags; + } + public BaseAnnotationReference getAnnotationReferences() { return annotationReferences; } @@ -47,6 +51,10 @@ public BaseFieldDeclarator getFieldDeclarators() { return fieldDeclarators; } + public void setFieldDeclarators(BaseFieldDeclarator fieldDeclarators) { + this.fieldDeclarators = fieldDeclarators; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java index cd595d93..7f106b32 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileFieldDeclaration.java @@ -33,14 +33,6 @@ public ClassFileFieldDeclaration(BaseAnnotationReference annotationReferences, i this.firstLineNumber = firstLineNumber; } - public void setFlags(int flags) { - this.flags = flags; - } - - public void setFieldDeclarators(BaseFieldDeclarator fieldDeclarators) { - this.fieldDeclarators = fieldDeclarators; - } - @Override public int getFirstLineNumber() { return firstLineNumber; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 844d0a3e..e3e5f6b3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -27,6 +27,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileMonitorExitStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.PrimitiveLocalVariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.EraseTypeArgumentVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; import org.jd.core.v1.util.DefaultList; import org.jd.core.v1.util.DefaultStack; @@ -46,9 +47,11 @@ public class ByteCodeParser { private MemberVisitor memberVisitor = new MemberVisitor(); private SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); + private EraseTypeArgumentVisitor eraseTypeArgumentVisitor = new EraseTypeArgumentVisitor(); private TypeMaker typeMaker; private LocalVariableMaker localVariableMaker; + protected boolean genericTypesSupported; private String internalTypeName; private TypeParametersToTypeArgumentsBinder typeParametersToTypeArgumentsBinder; private AttributeBootstrapMethods attributeBootstrapMethods; @@ -61,6 +64,7 @@ public ByteCodeParser( ClassFileBodyDeclaration bodyDeclaration, ClassFileConstructorOrMethodDeclaration comd) { this.typeMaker = typeMaker; this.localVariableMaker = localVariableMaker; + this.genericTypesSupported = (classFile.getMajorVersion() >= 49); // (majorVersion >= Java 5) this.internalTypeName = classFile.getInternalTypeName(); this.typeParametersToTypeArgumentsBinder = new TypeParametersToTypeArgumentsBinder(typeMaker, this.internalTypeName, comd); this.attributeBootstrapMethods = classFile.getAttribute("BootstrapMethods"); @@ -240,7 +244,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack0 ? type1.getDimension()-1 : 0); - typeParametersToTypeArgumentsBinder.bindParameterTypesWithArgumentTypes(type2, valueRef); + bindParameterTypesWithArgumentTypes(type2, valueRef); statements.add(new ExpressionStatement(new BinaryOperatorExpression(lineNumber, type2, new ArrayExpression(lineNumber, arrayRef, indexRef), "=", valueRef, 16))); break; case 84: // BASTORE @@ -265,7 +269,7 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack typeBounds, LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, - Statements statements, Expression condition, Statements subStatements, Statements jumps) { - Statement loop = makeLoop(typeBounds, localVariableMaker, loopBasicBlock, statements, condition, subStatements); + int majorVersion, Map typeBounds, LocalVariableMaker localVariableMaker, + BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements, + Statements jumps) { + Statement loop = makeLoop(majorVersion, typeBounds, localVariableMaker, loopBasicBlock, statements, condition, subStatements); int continueOffset = loopBasicBlock.getSub1().getFromOffset(); int breakOffset = loopBasicBlock.getNext().getFromOffset(); @@ -49,20 +50,24 @@ public static Statement makeLoop( } protected static Statement makeLoop( - Map typeBounds, LocalVariableMaker localVariableMaker, BasicBlock loopBasicBlock, - Statements statements, Expression condition, Statements subStatements) { + int majorVersion, Map typeBounds, LocalVariableMaker localVariableMaker, + BasicBlock loopBasicBlock, Statements statements, Expression condition, Statements subStatements) { + boolean forEachSupported = (majorVersion >= 49); // (majorVersion >= Java 5) + subStatements.accept(REMOVE_LAST_CONTINUE_STATEMENT_VISITOR); - Statement statement = makeForEachArray(typeBounds, localVariableMaker, statements, condition, subStatements); + if (forEachSupported) { + Statement statement = makeForEachArray(typeBounds, localVariableMaker, statements, condition, subStatements); - if (statement != null) { - return statement; - } + if (statement != null) { + return statement; + } - statement = makeForEachList(typeBounds, localVariableMaker, statements, condition, subStatements); + statement = makeForEachList(typeBounds, localVariableMaker, statements, condition, subStatements); - if (statement != null) { - return statement; + if (statement != null) { + return statement; + } } int lineNumber = (condition == null) ? Expression.UNKNOWN_LINE_NUMBER : condition.getLineNumber(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index a40a98b3..d43f8ad5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -626,7 +626,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st // 'while' or 'for' loop makeStatements(watchdog, ifBB.getCondition(), statements, jumps); statements.add(LoopStatementMaker.makeLoop( - typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), + majorVersion, typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getSub1(), statements, jumps, updateBasicBlock), jumps)); makeStatements(watchdog, basicBlock.getNext(), statements, jumps); return; @@ -647,7 +647,7 @@ protected void parseLoop(WatchDog watchdog, BasicBlock basicBlock, Statements st ifBB.getCondition().inverseCondition(); makeStatements(watchdog, ifBB.getCondition(), statements, jumps); statements.add(LoopStatementMaker.makeLoop( - typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), + majorVersion, typeBounds, localVariableMaker, basicBlock, statements, stack.pop(), makeSubStatements(watchdog, ifBB.getNext(), statements, jumps, updateBasicBlock), jumps)); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index 306229cc..a772bb4e 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -119,7 +119,7 @@ public FieldReferenceExpression newFieldReferenceExpression( bindings = createBindings(expression, typeParameters, typeArguments, null, TYPE_OBJECT, null, null, null); } - type = (Type) bind(bindings, type); + type = (Type)bind(bindings, type); } } } @@ -457,18 +457,12 @@ protected BaseType bind(Map bindings, BaseType parameterTy return parameterTypes; } - protected BaseType clone(BaseType parameterTypes) { + protected static BaseType clone(BaseType parameterTypes) { if ((parameterTypes != null) && parameterTypes.isList()) { switch (parameterTypes.size()) { - case 0: - parameterTypes = null; - break; - case 1: - parameterTypes = parameterTypes.getFirst(); - break; - default: - parameterTypes = new Types(parameterTypes.getList()); - break; + case 0: parameterTypes = null; break; + case 1: parameterTypes = parameterTypes.getFirst(); break; + default: parameterTypes = new Types(parameterTypes.getList()); break; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java deleted file mode 100644 index 1db0d389..00000000 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/BaseTypeToErasedTypeArgumentVisitor.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2008, 2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; - -import org.jd.core.v1.model.javasyntax.type.*; - -import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; - -public class BaseTypeToErasedTypeArgumentVisitor implements TypeVisitor { - protected TypeArgument typeArgument; - - public void init() { - this.typeArgument = null; - } - - public TypeArgument getTypeArgument() { - return typeArgument; - } - - @Override public void visit(PrimitiveType type) { typeArgument = type; } - @Override public void visit(ObjectType type) { typeArgument = type.createType(null); } - @Override public void visit(InnerObjectType type) { typeArgument = type.createType(null); } - @Override public void visit(GenericType type) { typeArgument = TYPE_OBJECT; } - - @Override - public void visit(Types types) { - if (types.isEmpty()) { - typeArgument = WildcardTypeArgument.WILDCARD_TYPE_ARGUMENT; - } else { - types.getFirst().accept(this); - } - } -} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/EraseTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/EraseTypeArgumentVisitor.java new file mode 100644 index 00000000..b32bd538 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/EraseTypeArgumentVisitor.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; + +public class EraseTypeArgumentVisitor implements TypeVisitor { + protected BaseType result; + + public void init() { + this.result = null; + } + + public BaseType getBaseType() { + return result; + } + + @Override public void visit(PrimitiveType type) { result = type; } + @Override public void visit(ObjectType type) { result = type.createType(null); } + @Override public void visit(GenericType type) { result = TYPE_OBJECT; } + + @Override public void visit(InnerObjectType type) { + Type t = type.getOuterType(); + + t.accept(this); + + if (result == t) { + result = type.createType(null); + } else { + result = new InnerObjectType(type.getInternalName(), type.getQualifiedName(), type.getName(), null, type.getDimension(), (ObjectType)result); + } + } + + @Override + public void visit(Types types) { + int size = types.size(); + int i; + + for (i=0; i syntheticInnerFieldNames = new DefaultList<>(); protected ObjectType outerType; @@ -72,7 +73,7 @@ public void visit(BodyDeclaration declaration) { } if ((outerType != null) || !syntheticInnerFieldNames.isEmpty()) { - updateFieldReferencesVisitor.visit(bodyDeclaration); + updateFieldDeclarationsAndReferencesVisitor.visit(bodyDeclaration); } } @@ -189,15 +190,36 @@ public void visit(ConstructorDeclaration declaration) { @Override public void visit(MethodDeclaration declaration) {} @Override public void visit(StaticInitializerDeclaration declaration) {} - protected class UpdateFieldReferencesVisitor extends AbstractUpdateExpressionVisitor { + protected class UpdateFieldDeclarationsAndReferencesVisitor extends AbstractUpdateExpressionVisitor { protected ClassFileBodyDeclaration bodyDeclaration; + protected boolean syntheticField; @Override public void visit(BodyDeclaration declaration) { bodyDeclaration = (ClassFileBodyDeclaration)declaration; + safeAcceptListDeclaration(bodyDeclaration.getFieldDeclarations()); safeAcceptListDeclaration(bodyDeclaration.getMethodDeclarations()); } + @Override + public void visit(FieldDeclaration declaration) { + syntheticField = false; + declaration.getFieldDeclarators().accept(this); + + if (syntheticField) { + declaration.setFlags(declaration.getFlags()|FLAG_SYNTHETIC); + } + } + + @Override + public void visit(FieldDeclarator declarator) { + String name = declarator.getName(); + + if (name.startsWith("this$") || syntheticInnerFieldNames.contains(name)) { + syntheticField = true; + } + } + @Override public void visit(StaticInitializerDeclaration declaration) {} @Override @@ -393,7 +415,7 @@ public void visit(NewExpression expression) { if ((type.getQualifiedName() == null) && (type.getName() != null)) { // Local class - cfcd.setFlags(cfcd.getFlags() & (~Declaration.FLAG_SYNTHETIC)); + cfcd.setFlags(cfcd.getFlags() & (~FLAG_SYNTHETIC)); localClassDeclarations.add(cfcd); bodyDeclaration.removeInnerType(internalName); lineNumber = ne.getLineNumber(); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java index 54daa49a..6f527277 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/ExpressionVisitor.java @@ -46,6 +46,7 @@ public class ExpressionVisitor extends TypeVisitor { protected LinkedList contextStack = new LinkedList<>(); protected Fragments fragments = new Fragments(); + protected boolean diamondOperatorSupported; protected boolean inExpressionFlag = false; protected HashSet currentMethodParamNames = new HashSet<>(); protected String currentTypeName; @@ -53,6 +54,7 @@ public class ExpressionVisitor extends TypeVisitor { public ExpressionVisitor(Loader loader, String mainInternalTypeName, int majorVersion, ImportsFragment importsFragment) { super(loader, mainInternalTypeName, majorVersion, importsFragment); + this.diamondOperatorSupported = (majorVersion >= 51); // (majorVersion >= Java 7) } public DefaultList getFragments() { @@ -474,7 +476,7 @@ public void visit(NewExpression expression) { ObjectType objectType = expression.getObjectType(); - if ((objectType.getTypeArguments() != null) && (bodyDeclaration == null) && (majorVersion >= 51)) { // (majorVersion >= Java 7) + if ((objectType.getTypeArguments() != null) && (bodyDeclaration == null) && diamondOperatorSupported) { objectType = objectType.createType(DiamondTypeArgument.DIAMOND); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java index 2df0765a..5af6e43a 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/TypeVisitor.java @@ -48,7 +48,7 @@ public class TypeVisitor extends AbstractJavaSyntaxVisitor { protected Loader loader; protected String internalPackageName; - protected int majorVersion; + protected boolean genericTypesSupported; protected ImportsFragment importsFragment; protected Tokens tokens; protected int maxLineNumber = 0; @@ -57,7 +57,7 @@ public class TypeVisitor extends AbstractJavaSyntaxVisitor { public TypeVisitor(Loader loader, String mainInternalTypeName, int majorVersion, ImportsFragment importsFragment) { this.loader = loader; - this.majorVersion = majorVersion; + this.genericTypesSupported = (majorVersion >= 49); // (majorVersion >= Java 5) this.importsFragment = importsFragment; int index = mainInternalTypeName.lastIndexOf('/'); @@ -106,7 +106,7 @@ public void visit(ObjectType type) { // Build token for type reference tokens.add(newTypeReferenceToken(type, currentInternalTypeName)); - if (majorVersion >= 49) { // (majorVersion >= Java 5) + if (genericTypesSupported) { // Build token for type arguments BaseTypeArgument typeArguments = type.getTypeArguments(); @@ -131,7 +131,7 @@ public void visit(InnerObjectType type) { // Build token for type reference tokens.add(new ReferenceToken(ReferenceToken.TYPE, type.getInternalName(), type.getName(), null, currentInternalTypeName)); - if (majorVersion >= 49) { // (majorVersion >= Java 5) + if (genericTypesSupported) { // Build token for type arguments BaseTypeArgument typeArguments = type.getTypeArguments(); @@ -154,16 +154,10 @@ protected void visitTypeArgumentList(BaseTypeArgument arguments) { protected void visitDimension(int dimension) { switch (dimension) { - case 0: - break; - case 1: - tokens.add(TextToken.DIMENSION_1); - break; - case 2: - tokens.add(TextToken.DIMENSION_2); - break; - default: - tokens.add(newTextToken(new String(new char[dimension]).replaceAll("\0", "[]"))); + case 0: break; + case 1: tokens.add(TextToken.DIMENSION_1); break; + case 2: tokens.add(TextToken.DIMENSION_2); break; + default: tokens.add(newTextToken(new String(new char[dimension]).replaceAll("\0", "[]"))); break; } } From 17ba0e026f13aa71faf3d8a2dce193b2209b8a1a Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sat, 11 Jan 2020 17:11:25 +0100 Subject: [PATCH 150/211] Add direct link to Bintray page --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 65682eda..7afc3830 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ JD-Core is a JAVA decompiler written in JAVA. - Java Decompiler project home page: -[http://java-decompiler.github.io](http://java-decompiler.github.io) +[http://java-decompiler.github.io](https://java-decompiler.github.io) - JD-Core source code: [https://github.com/java-decompiler/jd-core](https://github.com/java-decompiler/jd-core) - JCenter Maven repository: -[https://jcenter.bintray.com/](https://jcenter.bintray.com/) +[https://jcenter.bintray.com/](https://bintray.com/java-decompiler/maven/org.jd%3Ajd-core/_latestVersion) ## Description JD-Core is a standalone JAVA library containing the JAVA decompiler of From e8b7be6acca0d2c6fa521a3f2bf73815a686b5a5 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 13 Jan 2020 21:27:34 +0100 Subject: [PATCH 151/211] Fix missing nested class being created with outer name Previously ClassFileDeserializer would incorrectly create a ClassFile with the name of the enclosing class if a nested class could not be loaded. --- .../classfile/ClassFileDeserializer.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 09b99a27..7e5a7978 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -48,25 +48,27 @@ public ClassFile innerLoadClassFile(Loader loader, String internalTypeName) thro String innerTypePrefix = internalTypeName + '$'; for (InnerClass ic : aic.getInnerClasses()) { - if (!internalTypeName.equals(ic.getInnerTypeName())) { - if (internalTypeName.equals(ic.getOuterTypeName()) || ic.getInnerTypeName().startsWith(innerTypePrefix)) { - ClassFile innerClassFile = innerLoadClassFile(loader, ic.getInnerTypeName()); + String innerTypeName = ic.getInnerTypeName(); + + if (!internalTypeName.equals(innerTypeName)) { + if (internalTypeName.equals(ic.getOuterTypeName()) || innerTypeName.startsWith(innerTypePrefix)) { + ClassFile innerClassFile = innerLoadClassFile(loader, innerTypeName); int flags = ic.getInnerAccessFlags(); int length; - if (ic.getInnerTypeName().startsWith(innerTypePrefix)) { + if (innerTypeName.startsWith(innerTypePrefix)) { length = internalTypeName.length() + 1; } else { - length = ic.getInnerTypeName().indexOf('$') + 1; + length = innerTypeName.indexOf('$') + 1; } - if (Character.isDigit(ic.getInnerTypeName().charAt(length))) { + if (Character.isDigit(innerTypeName.charAt(length))) { flags |= ACC_SYNTHETIC; } if (innerClassFile == null) { // Inner class not found. Create an empty one. - innerClassFile = new ClassFile(classFile.getMajorVersion(), classFile.getMinorVersion(), 0, internalTypeName, "java/lang/Object", null, null, null, null); + innerClassFile = new ClassFile(classFile.getMajorVersion(), classFile.getMinorVersion(), 0, innerTypeName, "java/lang/Object", null, null, null, null); } innerClassFile.setOuterClassFile(classFile); From 38a13821f4ce9ab4fe1d9cc32c721a7f51728e2d Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 13 Jan 2020 20:45:41 +0100 Subject: [PATCH 152/211] Throw descriptive exception when class to decompile cannot be loaded Previously a not descriptive NullPointerException was thrown. Also ClassFileDeserializer would try to load classes without checking if they can be loaded. --- .../classfile/ClassFileDeserializer.java | 15 +++++++++-- .../jd/core/v1/ClassFileDeserializerTest.java | 27 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 09b99a27..ae57150f 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -25,10 +25,21 @@ public class ClassFileDeserializer { protected static final int[] EMPTY_INT_ARRAY = new int[0]; public ClassFile loadClassFile(Loader loader, String internalTypeName) throws Exception { - return innerLoadClassFile(loader, internalTypeName); + ClassFile classFile = innerLoadClassFile(loader, internalTypeName); + + if (classFile == null) { + throw new IllegalArgumentException("Class '" + internalTypeName + "' could not be loaded"); + } + else { + return classFile; + } } - public ClassFile innerLoadClassFile(Loader loader, String internalTypeName) throws Exception { + private ClassFile innerLoadClassFile(Loader loader, String internalTypeName) throws Exception { + if (!loader.canLoad(internalTypeName)) { + return null; + } + byte[] data = loader.load(internalTypeName); if (data == null) { diff --git a/src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java b/src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java index 1e61e292..c8aa3fcf 100644 --- a/src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileDeserializerTest.java @@ -8,6 +8,9 @@ package org.jd.core.v1; import junit.framework.TestCase; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; import org.jd.core.v1.loader.ZipLoader; import org.jd.core.v1.model.classfile.ClassFile; import org.jd.core.v1.model.classfile.Field; @@ -17,12 +20,36 @@ import org.jd.core.v1.model.classfile.constant.ConstantInteger; import org.jd.core.v1.model.classfile.constant.ConstantUtf8; import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.service.deserializer.classfile.ClassFileDeserializer; import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; import org.junit.Test; import java.io.InputStream; public class ClassFileDeserializerTest extends TestCase { + @Test + public void testMissingClass() throws Exception { + class NoOpLoader implements Loader { + @Override + public boolean canLoad(String internalName) { + return false; + } + + @Override + public byte[] load(String internalName) throws LoaderException { + fail("Loader cannot load anything"); + return null; + } + } + + ClassFileDeserializer deserializer = new ClassFileDeserializer(); + try { + deserializer.loadClassFile(new NoOpLoader(), "DoesNotExist"); + fail("Expected exception"); + } + // Expecting exception because class cannot be loaded + catch (IllegalArgumentException expected) { } + } @Test public void testAnnotatedClass() throws Exception { From e28cbf8add835436e2388944123f63c7a2c4a222 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Tue, 14 Jan 2020 01:02:07 +0100 Subject: [PATCH 153/211] Remove recursive and redundant equals methods Equals methods calling themselves would cause infinite recursion. Equals methods checking `this == obj` are the same as the default implementation and are therefore redundant. --- .../org/jd/core/v1/model/javafragment/ImportsFragment.java | 4 +--- .../util/ControlFlowGraphLoopReducer.java | 5 ----- .../classfiletojavasyntax/util/ControlFlowGraphMaker.java | 5 ----- .../visitor/TokenizeJavaFragmentVisitor.java | 4 +--- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java index 6333a399..e4ae0d32 100644 --- a/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java +++ b/src/main/java/org/jd/core/v1/model/javafragment/ImportsFragment.java @@ -111,11 +111,9 @@ public void accept(JavaFragmentVisitor visitor) { } protected static class ImportCountComparator implements Comparator { + @Override public int compare(Import tr1, Import tr2) { return tr2.getCounter() - tr1.getCounter(); } - public boolean equals(Object obj) { - return this.equals(obj); - } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphLoopReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphLoopReducer.java index 85fba5d4..67f70aeb 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphLoopReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphLoopReducer.java @@ -720,10 +720,5 @@ public static class LoopComparator implements Comparator { public int compare(Loop loop1, Loop loop2) { return loop1.getMembers().size() - loop2.getMembers().size(); } - - @Override - public boolean equals(Object other) { - return this==other; - } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java index b85f70d1..4f20e897 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java @@ -588,10 +588,5 @@ public int compare(CodeException ce1, CodeException ce2) { comp = ce1.getEndPc() - ce2.getEndPc(); return comp; } - - @Override - public boolean equals(Object other) { - return this==other; - } } } diff --git a/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java b/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java index e398eeb7..b2a33843 100644 --- a/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java +++ b/src/main/java/org/jd/core/v1/service/tokenizer/javafragmenttotoken/visitor/TokenizeJavaFragmentVisitor.java @@ -517,12 +517,10 @@ public void visit(TokensFragment fragment) { } protected static class ImportNameComparator implements Comparator { + @Override public int compare(ImportsFragment.Import tr1, ImportsFragment.Import tr2) { return tr1.getQualifiedName().compareTo(tr2.getQualifiedName()); } - public boolean equals(Object obj) { - return this.equals(obj); - } } protected class KnownLineNumberTokenVisitor extends AbstractNopTokenVisitor { From 93d8aed0bbf6350fcb1c04215a447b3ee17ff06e Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 20 Jan 2020 18:20:46 +0100 Subject: [PATCH 154/211] Fix syntax errors in decompiled sources --- build.gradle | 16 +- .../model/localvariable/Frame.java | 45 ++++-- .../localvariable/ObjectLocalVariable.java | 39 ++--- .../model/localvariable/RootFrame.java | 4 +- .../util/ByteCodeParser.java | 152 +++++++++++++++++- .../util/ControlFlowGraphReducer.java | 88 +++++++++- .../util/LocalVariableMaker.java | 4 +- .../util/StatementMaker.java | 20 ++- .../util/SwitchStatementMaker.java | 34 +++- .../TypeParametersToTypeArgumentsBinder.java | 22 ++- .../visitor/AddCastExpressionVisitor.java | 13 +- .../visitor/CreateInstructionsVisitor.java | 11 +- .../visitor/GetTypeArgumentVisitor.java | 29 ++++ .../visitor/InitStaticFieldVisitor.java | 112 +++++-------- .../visitor/RenameLocalVariablesVisitor.java | 62 +++++++ .../SearchUndeclaredLocalVariableVisitor.java | 13 -- .../JavaSyntaxToJavaFragmentProcessor.java | 2 +- .../visitor/SearchImportsVisitor.java | 13 +- .../jd/core/v1/ClassFileToJavaSourceTest.java | 43 ++++- .../jd/core/v1/JarFileToJavaSourceTest.java | 65 +++++++- .../cfg/ControlFlowGraphPlantUMLWriter.java | 4 + 21 files changed, 621 insertions(+), 170 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GetTypeArgumentVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RenameLocalVariablesVisitor.java diff --git a/build.gradle b/build.gradle index 1d989da2..b2225bfb 100644 --- a/build.gradle +++ b/build.gradle @@ -7,10 +7,22 @@ apply plugin: 'com.jfrog.bintray' dependencies { testCompile 'commons-codec:commons-codec:1.13' testCompile 'org.apache.commons:commons-collections4:4.1' + testCompile 'org.apache.commons:commons-imaging:1.0-alpha1' testCompile 'org.apache.commons:commons-lang3:3.9' + testCompile 'com.jakewharton:disklrucache:2.0.2' testCompile 'com.squareup:javapoet:1.11.1' + testCompile 'com.squareup:javawriter:2.5.1' + testCompile 'joda-time:joda-time:2.10.5' + testCompile 'org.joda:joda-convert:2.2.1' testCompile 'org.jsoup:jsoup:1.12.1' testCompile 'junit:junit:4.12' + testCompile 'javax.jms:javax.jms-api:2.0.1' + testCompile 'javax.mail:javax.mail-api:1.6.2' + testCompile 'com.squareup.mimecraft:mimecraft:1.1.1' + testCompile 'org.scribe:scribe:1.3.7' + testCompile 'com.sparkjava:spark-core:2.9.1' + testCompile 'log4j:log4j:1.2.17' + testCompile 'com.google.guava:guava:12.0' } version='1.1.4' @@ -18,8 +30,8 @@ version='1.1.4' tasks.withType(JavaCompile) { sourceCompatibility = targetCompatibility = '1.8' options.compilerArgs << '-Xlint:deprecation' - options.compilerArgs << '-Xlint:unchecked' - options.encoding = 'UTF-8' + options.compilerArgs << '-Xlint:unchecked' + options.encoding = 'UTF-8' } buildscript { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 5ec878c2..8432aece 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -19,6 +19,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileSuperConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.LocalVariableMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchUndeclaredLocalVariableVisitor; import org.jd.core.v1.util.DefaultList; @@ -117,24 +118,40 @@ public void mergeLocalVariable(Map typeBounds, LocalVariableMa lv.getReferences().addAll(alvToMerge.getReferences()); lv.setFromOffset(alvToMerge.getFromOffset()); - if (!lv.isAssignableFrom(typeBounds, alvToMerge) && !localVariableMaker.isCompatible(lv, alvToMerge.getType())) { - Type type = lv.getType(); - Type alvToMergeType = alvToMerge.getType(); + Type type = lv.getType(); + Type alvToMergeType = alvToMerge.getType(); + if (lv.isAssignableFrom(typeBounds, alvToMerge) || localVariableMaker.isCompatible(lv, alvToMerge.getType())) { + if (type.isPrimitive()) { + PrimitiveLocalVariable plv = (PrimitiveLocalVariable)lv; + PrimitiveLocalVariable plvToMergeType = (PrimitiveLocalVariable)alvToMerge; + Type t = PrimitiveTypeUtil.getCommonPrimitiveType((PrimitiveType)plv.getType(), (PrimitiveType)plvToMergeType.getType()); + + if (t == null) { + t = PrimitiveType.TYPE_INT; + } + + plv.setType((PrimitiveType)t.createType(type.getDimension())); + } + } else { assert (type.isPrimitive() == alvToMergeType.isPrimitive()) && (type.isObject() == alvToMergeType.isObject()) && (type.isGeneric() == alvToMergeType.isGeneric()) : "Frame.mergeLocalVariable(lv) : merge local variable failed"; if (type.isPrimitive()) { + PrimitiveLocalVariable plv = (PrimitiveLocalVariable)lv; + if (alvToMerge.isAssignableFrom(typeBounds, lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { - ((PrimitiveLocalVariable)lv).setType((PrimitiveType)alvToMergeType); + plv.setType((PrimitiveType)alvToMergeType); } else { - ((PrimitiveLocalVariable)lv).setType(PrimitiveType.TYPE_INT); + plv.setType(PrimitiveType.TYPE_INT); } } else if (type.isObject()) { + ObjectLocalVariable olv = (ObjectLocalVariable)lv; + if (alvToMerge.isAssignableFrom(typeBounds, lv) || localVariableMaker.isCompatible(alvToMerge, lv.getType())) { - ((ObjectLocalVariable)lv).setType(typeBounds, alvToMergeType); + olv.setType(typeBounds, alvToMergeType); } else { int dimension = Math.max(lv.getDimension(), alvToMerge.getDimension()); - ((ObjectLocalVariable)lv).setType(typeBounds, ObjectType.TYPE_OBJECT.createType(dimension)); + olv.setType(typeBounds, ObjectType.TYPE_OBJECT.createType(dimension)); } } } @@ -253,9 +270,9 @@ public void createNames(HashSet parentNames) { } } - public void createDeclarations() { + public void createDeclarations(boolean containsLineNumber) { // Create inline declarations - boolean containsLineNumber = createInlineDeclarations(); + createInlineDeclarations(); // Create start-block declarations createStartBlockDeclarations(); @@ -268,14 +285,13 @@ public void createDeclarations() { // Recursive call if (children != null) { for (Frame child : children) { - child.createDeclarations(); + child.createDeclarations(containsLineNumber); } } } @SuppressWarnings("unchecked") - protected boolean createInlineDeclarations() { - boolean containsLineNumber = false; + protected void createInlineDeclarations() { HashMap> map = createMapForInlineDeclarations(); if (!map.isEmpty()) { @@ -292,7 +308,6 @@ protected boolean createInlineDeclarations() { visitor.init(); statement.accept(visitor); - containsLineNumber |= visitor.containsLineNumber(); HashSet undeclaredLocalVariablesInStatement = visitor.getVariables(); undeclaredLocalVariablesInStatement.retainAll(undeclaredLocalVariables); @@ -337,8 +352,6 @@ protected boolean createInlineDeclarations() { } } } - - return containsLineNumber; } protected HashMap> createMapForInlineDeclarations() { @@ -676,7 +689,7 @@ protected void mergeDeclarations() { LocalVariableDeclarationStatement lvds2 = (LocalVariableDeclarationStatement) statement; int lineNumber2 = lvds2.getLocalVariableDeclarators().getLineNumber(); - if ((lineNumber1 != lineNumber2) && (lineNumber1 > 0)) { + if (lineNumber1 != lineNumber2) { iterator.previous(); break; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java index 1fdba8a9..c980bf72 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/ObjectLocalVariable.java @@ -143,29 +143,22 @@ public void typeOnLeft(Map typeBounds, Type type) { if (this.type == TYPE_UNDEFINED_OBJECT) { this.type = type; fireChangeEvent(typeBounds); - } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0)) { - assert !this.type.isPrimitive() && !type.isPrimitive() : "unexpected type in ObjectLocalVariable.typeOnLeft(type)"; - - if (this.type.isObject()) { - ObjectType thisObjectType = (ObjectType) this.type; - - if (type.isObject()) { - ObjectType otherObjectType = (ObjectType) type; - - if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { - if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { - // Keep type, update type arguments - this.type = otherObjectType; - fireChangeEvent(typeBounds); - } - } else if (typeMaker.isAssignable(typeBounds, otherObjectType, thisObjectType)) { - // Assignable types - if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { - // Keep type, update type arguments - this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); - fireChangeEvent(typeBounds); - } - } + } else if ((this.type.getDimension() == 0) && (type.getDimension() == 0) && this.type.isObject() && type.isObject()) { + ObjectType thisObjectType = (ObjectType) this.type; + ObjectType otherObjectType = (ObjectType) type; + + if (thisObjectType.getInternalName().equals(otherObjectType.getInternalName())) { + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = otherObjectType; + fireChangeEvent(typeBounds); + } + } else if (typeMaker.isAssignable(typeBounds, otherObjectType, thisObjectType)) { + // Assignable types + if ((thisObjectType.getTypeArguments() == null) && (otherObjectType.getTypeArguments() != null)) { + // Keep type, update type arguments + this.type = thisObjectType.createType(otherObjectType.getTypeArguments()); + fireChangeEvent(typeBounds); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java index 2b63d2f2..5a24e0c9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java @@ -20,10 +20,10 @@ public AbstractLocalVariable getLocalVariable(int index) { return null; } - public void createDeclarations() { + public void createDeclarations(boolean containsLineNumber) { if (children != null) { for (Frame child : children) { - child.createDeclarations(); + child.createDeclarations(containsLineNumber); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index e3e5f6b3..8ab0c9e4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -28,6 +28,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.PrimitiveLocalVariable; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.EraseTypeArgumentVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.RenameLocalVariablesVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchFirstLineNumberVisitor; import org.jd.core.v1.util.DefaultList; import org.jd.core.v1.util.DefaultStack; @@ -38,6 +39,7 @@ import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_STATIC; import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_SYNTHETIC; import static org.jd.core.v1.model.javasyntax.statement.ReturnStatement.RETURN; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_CLASS; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; @@ -48,6 +50,8 @@ public class ByteCodeParser { private MemberVisitor memberVisitor = new MemberVisitor(); private SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); private EraseTypeArgumentVisitor eraseTypeArgumentVisitor = new EraseTypeArgumentVisitor(); + private LambdaParameterNamesVisitor lambdaParameterNamesVisitor = new LambdaParameterNamesVisitor();; + private RenameLocalVariablesVisitor renameLocalVariablesVisitor = new RenameLocalVariablesVisitor(); private TypeMaker typeMaker; private LocalVariableMaker localVariableMaker; @@ -799,6 +803,12 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack stack.push(new LambdaIdentifiersExpression( lineNumber, indyMethodTypes.returnedType, indyMethodTypes.returnedType, prepareLambdaParameters(cfmd.getFormalParameters(), parameterCount), - prepareLambdaStatements(cfmd.getStatements()))); + prepareLambdaStatements(cfmd.getFormalParameters(), indyParameters, cfmd.getStatements()))); return; } } @@ -1354,11 +1364,11 @@ private void parseInvokeDynamic(Statements statements, DefaultStack stack.push(new MethodReferenceExpression(lineNumber, indyMethodTypes.returnedType, (Expression)indyParameters, typeName, name1, descriptor1)); } - private static List prepareLambdaParameters(BaseFormalParameter formalParameters, int parameterCount) { + private List prepareLambdaParameters(BaseFormalParameter formalParameters, int parameterCount) { if ((formalParameters == null) || (parameterCount == 0)) { return null; } else { - LambdaParameterNamesVisitor lambdaParameterNamesVisitor = new LambdaParameterNamesVisitor(); + lambdaParameterNamesVisitor.init(); formalParameters.accept(lambdaParameterNamesVisitor); List names = lambdaParameterNamesVisitor.getNames(); @@ -1372,8 +1382,49 @@ private static List prepareLambdaParameters(BaseFormalParameter formalPa } } - private static BaseStatement prepareLambdaStatements(BaseStatement baseStatement) { - if ((baseStatement != null) && baseStatement.isList()) { + private BaseStatement prepareLambdaStatements(BaseFormalParameter formalParameters, BaseExpression indyParameters, BaseStatement baseStatement) { + if (baseStatement != null) { + if ((formalParameters != null) && (indyParameters != null)) { + int size = indyParameters.size(); + + if ((size > 0) && (size <= formalParameters.size())) { + HashMap mapping = new HashMap<>(); + Expression expression = indyParameters.getFirst(); + + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + String name = formalParameters.getFirst().getName(); + String newName = ((ClassFileLocalVariableReferenceExpression) expression).getName(); + + if (!name.equals(newName)) { + mapping.put(name, newName); + } + } + + if (size > 1) { + DefaultList formalParameterList = formalParameters.getList(); + DefaultList list = indyParameters.getList(); + + for (int i = 1; i < size; i++) { + expression = list.get(i); + + if (expression.getClass() == ClassFileLocalVariableReferenceExpression.class) { + String name = formalParameterList.get(i).getName(); + String newName = ((ClassFileLocalVariableReferenceExpression) expression).getName(); + + if (!name.equals(newName)) { + mapping.put(name, newName); + } + } + } + } + + if (!mapping.isEmpty()) { + renameLocalVariablesVisitor.init(mapping); + baseStatement.accept(renameLocalVariablesVisitor); + } + } + } + if (baseStatement.size() == 1) { Statement statement = baseStatement.getFirst(); @@ -2438,6 +2489,93 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock return depth; } + public static int getOperandCount(BasicBlock bb) { + Method method = bb.getControlFlowGraph().getMethod(); + ConstantPool constants = method.getConstants(); + AttributeCode attributeCode = method.getAttribute("Code"); + byte[] code = attributeCode.getCode(); + return getOperandCount(constants, code, bb); + } + + private static int getOperandCount(ConstantPool constants, byte[] code, BasicBlock bb) { + ConstantMemberRef constantMemberRef; + ConstantNameAndType constantNameAndType; + String descriptor; + int offset = bb.getFromOffset(); + int opcode = code[offset] & 255; + + switch (opcode) { + case 89: // DUP + case 59: case 60: case 61: case 62: // ISTORE_0 ... ISTORE_3 + case 63: case 64: case 65: case 66: // LSTORE_0 ... LSTORE_3 + case 67: case 68: case 69: case 70: // FSTORE_0 ... FSTORE_3 + case 71: case 72: case 73: case 74: // DSTORE_0 ... DSTORE_3 + case 75: case 76: case 77: case 78: // ASTORE_0 ... ASTORE_3 + case 87: // POP + case 172: case 173: case 174: case 175: case 176: // IRETURN, LRETURN, FRETURN, DRETURN, ARETURN + case 194: case 195: // MONITORENTER, MONITOREXIT + case 153: case 154: case 155: case 156: case 157: case 158: // IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE + case 179: // PUTSTATIC + case 198: case 199: // IFNULL, IFNONNULL + case 54: case 55: case 56: case 57: case 58: // ISTORE, LSTORE, FSTORE, DSTORE, ASTORE + case 180: // GETFIELD + case 189: // ANEWARRAY + case 192: // CHECKCAST + case 193: // INSTANCEOF + case 188: // NEWARRAY + case 170: // TABLESWITCH + case 171: // LOOKUPSWITCH + return 1; + case 90: // DUP_X1 + case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: // IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD + case 96: case 97: case 98: case 99: // IADD, LADD, FADD, DADD + case 100: case 101: case 102: case 103: // ISUB, LSUB, FSUB, DSUB + case 104: case 105: case 106: case 107: // IMUL, LMUL, FMUL, DMUL + case 108: case 109: case 110: case 111: // IDIV, LDIV, FDIV, DDIV + case 112: case 113: case 114: case 115: // IREM, LREM, FREM, DREM + case 120: case 121: // ISHL, LSHL + case 122: case 123: // ISHR, LSHR + case 124: case 125: // IUSHR, LUSHR + case 126: case 127: // IAND, LAND + case 128: case 129: // IOR, LOR + case 130: case 131: // IXOR, LXOR + case 148: case 149: case 150: case 151: case 152: // LCMP, FCMPL, FCMPG, DCMPL, DCMPG + case 92: // DUP2 + case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: // IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE + case 181: // PUTFIELD + case 88: // POP2 + return 2; + case 91: // DUP_X2 + case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: // IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE + case 93: // DUP2_X1 + return 3; + case 94: // DUP2_X2 + return 4; + case 182: case 183: case 185: // INVOKEVIRTUAL, INVOKESPECIAL, INVOKEINTERFACE + constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); + constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); + return 1 + countMethodParameters(descriptor); + case 184: case 186: // INVOKESTATIC, INVOKEDYNAMIC + constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); + constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); + return countMethodParameters(descriptor); + case 196: // WIDE + opcode = code[++offset] & 255; + switch (opcode) { + case 54: case 55: case 56: case 57: case 58: // ISTORE, LSTORE, FSTORE, DSTORE, ASTORE + return 1; + } + break; + case 197: // MULTIANEWARRAY + offset += 3; + return (code[offset] & 255); + } + + return 0; + } + private static int countMethodParameters(String descriptor) { int count = 0; int i = 2; @@ -2488,9 +2626,9 @@ public void visit(MethodDeclaration declaration) { } private static class LambdaParameterNamesVisitor extends AbstractNopDeclarationVisitor { - protected DefaultList names = new DefaultList<>(); + protected DefaultList names; - public void reset() { + public void init() { names = new DefaultList<>(); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 1ee771be..7808162d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -215,6 +215,10 @@ protected static boolean reduceConditionalBranch(BasicBlock basicBlock) { protected static void createIf(BasicBlock basicBlock, BasicBlock sub, BasicBlock last, BasicBlock next) { BasicBlock condition = basicBlock.getControlFlowGraph().newBasicBlock(basicBlock); + + condition.setNext(END); + condition.setBranch(END); + int toOffset = last.getToOffset(); if (toOffset == 0) { @@ -235,6 +239,10 @@ protected static void createIf(BasicBlock basicBlock, BasicBlock sub, BasicBlock protected static void createIfElse(int type, BasicBlock basicBlock, BasicBlock sub1, BasicBlock last1, BasicBlock sub2, BasicBlock last2, BasicBlock next) { BasicBlock condition = basicBlock.getControlFlowGraph().newBasicBlock(basicBlock); + + condition.setNext(END); + condition.setBranch(END); + int toOffset = last2.getToOffset(); if (toOffset == 0) { @@ -271,13 +279,26 @@ protected static boolean aggregateConditionalBranches(BasicBlock basicBlock) { if (nextNext.matchType(TYPE_CONDITIONAL_BRANCH|TYPE_CONDITION)) { if (branch.matchType(TYPE_STATEMENTS|TYPE_GOTO_IN_TERNARY_OPERATOR) && (nextNext == branch.getNext()) && (branch.getPredecessors().size() == 1) && (nextNext.getPredecessors().size() == 2)) { - int stackDepth = ByteCodeParser.evalStackDepth(basicBlock); - int stackDepthNextNext = ByteCodeParser.evalStackDepth(nextNext); - - if (stackDepth+1 == -stackDepthNextNext) { + if (ByteCodeParser.getOperandCount(nextNext) == 1) { updateConditionTernaryOperator(basicBlock, nextNext); return true; } + + BasicBlock nextNextNext = nextNext.getNext(); + BasicBlock nextNextBranch = nextNext.getBranch(); + + if ((nextNextNext.getType() == TYPE_GOTO_IN_TERNARY_OPERATOR) && (nextNextNext.getPredecessors().size() == 1)) { + BasicBlock nextNextNextNext = nextNextNext.getNext(); + + if (nextNextNextNext.matchType(TYPE_CONDITIONAL_BRANCH|TYPE_CONDITION)) { + if (nextNextBranch.matchType(TYPE_STATEMENTS|TYPE_GOTO_IN_TERNARY_OPERATOR) && (nextNextNextNext == nextNextBranch.getNext()) && (nextNextBranch.getPredecessors().size() == 1) && (nextNextNextNext.getPredecessors().size() == 2)) { + if (ByteCodeParser.getOperandCount(nextNextNextNext) == 2) { + updateCondition(basicBlock, nextNext, nextNextNextNext); + return true; + } + } + } + } } if ((nextNext.getNext() == branch) && checkJdk118TernaryOperatorPattern(next, nextNext, 153)) { // IFEQ convertConditionalBranchToGotoInTernaryOperator(basicBlock, next, nextNext); @@ -431,6 +452,62 @@ protected static void updateConditionTernaryOperator(BasicBlock basicBlock, Basi basicBlock.getSub2().getPredecessors().clear(); } + protected static void updateCondition(BasicBlock basicBlock, BasicBlock nextNext, BasicBlock nextNextNextNext) { + int fromOffset = nextNextNextNext.getFromOffset(); + int toOffset = nextNextNextNext.getToOffset(); + BasicBlock next = nextNextNextNext.getNext(); + BasicBlock branch = nextNextNextNext.getBranch(); + + BasicBlock condition = basicBlock.getControlFlowGraph().newBasicBlock(basicBlock); + condition.setType(TYPE_CONDITION); + + basicBlock.getNext().setNext(END); + basicBlock.getNext().getPredecessors().clear(); + basicBlock.getBranch().setNext(END); + basicBlock.getBranch().getPredecessors().clear(); + + nextNextNextNext.setType(TYPE_CONDITION_TERNARY_OPERATOR); + nextNextNextNext.setFromOffset(condition.getToOffset()); + nextNextNextNext.setToOffset(condition.getToOffset()); + nextNextNextNext.setCondition(condition); + nextNextNextNext.setSub1(basicBlock.getNext()); + nextNextNextNext.setSub2(basicBlock.getBranch()); + nextNextNextNext.setNext(END); + nextNextNextNext.setBranch(END); + condition.setNext(END); + condition.setBranch(END); + + condition = nextNext.getControlFlowGraph().newBasicBlock(nextNext); + condition.setType(TYPE_CONDITION); + + nextNext.getNext().setNext(END); + nextNext.getNext().getPredecessors().clear(); + nextNext.getBranch().setNext(END); + nextNext.getBranch().getPredecessors().clear(); + + nextNext.setType(TYPE_CONDITION_TERNARY_OPERATOR); + nextNext.setFromOffset(condition.getToOffset()); + nextNext.setToOffset(condition.getToOffset()); + nextNext.setCondition(condition); + nextNext.setSub1(nextNext.getNext()); + nextNext.setSub2(nextNext.getBranch()); + nextNext.setNext(END); + nextNext.setBranch(END); + condition.setNext(END); + condition.setBranch(END); + + basicBlock.setType(TYPE_CONDITION); + basicBlock.setFromOffset(fromOffset); + basicBlock.setToOffset(toOffset); + basicBlock.setSub1(nextNextNextNext); + basicBlock.setSub2(nextNext); + basicBlock.setNext(next); + basicBlock.setBranch(branch); + + next.replace(nextNextNextNext, basicBlock); + branch.replace(nextNextNextNext, basicBlock); + } + protected static void updateConditionTernaryOperator2(BasicBlock basicBlock) { BasicBlock next = basicBlock.getNext(); BasicBlock branch = basicBlock.getBranch(); @@ -438,6 +515,9 @@ protected static void updateConditionTernaryOperator2(BasicBlock basicBlock) { ControlFlowGraph cfg = basicBlock.getControlFlowGraph(); BasicBlock condition = cfg.newBasicBlock(TYPE_CONDITION, basicBlock.getFromOffset(), basicBlock.getToOffset()); + condition.setNext(END); + condition.setBranch(END); + basicBlock.setType(TYPE_CONDITION_TERNARY_OPERATOR); basicBlock.setToOffset(basicBlock.getFromOffset()); basicBlock.setCondition(condition); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index bbbb1740..1caa6109 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -493,9 +493,9 @@ public boolean containsName(String name) { return names.contains(name); } - public void make() { + public void make(boolean containsLineNumber) { currentFrame.createNames(blackListNames); - currentFrame.createDeclarations(); + currentFrame.createDeclarations(containsLineNumber); } public BaseFormalParameter getFormalParameters() { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index d43f8ad5..801e3394 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -195,6 +195,12 @@ protected void makeStatements(WatchDog watchdog, BasicBlock basicBlock, Statemen makeStatements(watchdog, basicBlock.getNext(), statements, jumps); break; case TYPE_CONDITION: + if (basicBlock.getSub1() != END) { + stack.push(makeExpression(watchdog, basicBlock.getSub1(), statements, jumps)); + } + if (basicBlock.getSub2() != END) { + stack.push(makeExpression(watchdog, basicBlock.getSub2(), statements, jumps)); + } parseByteCode(basicBlock, statements); break; case TYPE_CONDITION_OR: @@ -897,7 +903,19 @@ protected TernaryOperatorExpression newTernaryOperatorExpression(int lineNumber, } else if ((flags & FLAG_LONG) != 0) { type = TYPE_LONG; } else { - type = MAYBE_BOOLEAN_TYPE; + flags = ((PrimitiveType)expressionTrueType).getFlags() & ((PrimitiveType)expressionFalseType).getFlags(); + + if ((flags & FLAG_INT) != 0) { + type = TYPE_INT; + } else if ((flags & FLAG_SHORT) != 0) { + type = TYPE_SHORT; + } else if ((flags & FLAG_CHAR) != 0) { + type = TYPE_CHAR; + } else if ((flags & FLAG_BYTE) != 0) { + type = TYPE_BYTE; + } else { + type = MAYBE_BOOLEAN_TYPE; + } } } else if (expressionTrueType.isObject() && expressionFalseType.isObject()) { ObjectType ot1 = (ObjectType)expressionTrueType; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java index 6b7fb963..df726ea3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/SwitchStatementMaker.java @@ -20,7 +20,7 @@ import org.jd.core.v1.util.DefaultList; import java.util.HashMap; -import java.util.ListIterator; +import java.util.Iterator; public class SwitchStatementMaker { protected static final Integer MINUS_ONE = Integer.valueOf(-1); @@ -193,7 +193,7 @@ public static void makeSwitchEnum(ClassFileBodyDeclaration bodyDeclaration, Swit // Javac switch-enum pattern bodyDeclaration = (ClassFileBodyDeclaration) syntheticClassDeclaration.getBodyDeclaration(); DefaultList statements = bodyDeclaration.getMethodDeclarations().get(0).getStatements().getList(); - updateSwitchStatement(switchStatement, statements.listIterator(1)); + updateSwitchStatement(switchStatement, searchSwitchMap(fre, statements.iterator())); } } } else if (expressionClass == ClassFileMethodInvocationExpression.class) { @@ -213,7 +213,35 @@ public static void makeSwitchEnum(ClassFileBodyDeclaration bodyDeclaration, Swit } } - protected static void updateSwitchStatement(SwitchStatement switchStatement, ListIterator iterator) { + protected static Iterator searchSwitchMap(FieldReferenceExpression fre, Iterator iterator) { + String name = fre.getName(); + + while (iterator.hasNext()) { + Statement statement = iterator.next(); + + if (statement.getClass() == ExpressionStatement.class) { + Expression expression = ((ExpressionStatement)statement).getExpression(); + + if (expression.getClass() == BinaryOperatorExpression.class) { + BinaryOperatorExpression boe = (BinaryOperatorExpression)expression; + + expression = boe.getLeftExpression(); + + if (expression.getClass() == FieldReferenceExpression.class) { + fre = (FieldReferenceExpression)expression; + + if (name.equals(fre.getName())) { + return iterator; + } + } + } + } + } + + return iterator; + } + + protected static void updateSwitchStatement(SwitchStatement switchStatement, Iterator iterator) { // Create map enum name> HashMap map = new HashMap<>(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java index a772bb4e..550e2cdd 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/TypeParametersToTypeArgumentsBinder.java @@ -18,6 +18,7 @@ import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_STATIC; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_OBJECT; +import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_STRING; import static org.jd.core.v1.model.javasyntax.type.ObjectType.TYPE_UNDEFINED_OBJECT; public class TypeParametersToTypeArgumentsBinder { @@ -28,6 +29,7 @@ public class TypeParametersToTypeArgumentsBinder { protected SearchInTypeArgumentVisitor searchInTypeArgumentVisitor = new SearchInTypeArgumentVisitor(); protected TypeArgumentToTypeVisitor typeArgumentToTypeVisitor = new TypeArgumentToTypeVisitor(); protected BaseTypeToTypeArgumentVisitor baseTypeToTypeArgumentVisitor = new BaseTypeToTypeArgumentVisitor(); + protected GetTypeArgumentVisitor getTypeArgumentVisitor = new GetTypeArgumentVisitor(); protected BindTypeParametersToNonWildcardTypeArgumentsVisitor bindTypeParametersToNonWildcardTypeArgumentsVisitor = new BindTypeParametersToNonWildcardTypeArgumentsVisitor(); protected BindVisitor bindVisitor = new BindVisitor(); @@ -184,7 +186,15 @@ protected void bind(Type type, ClassFileMethodInvocationExpression mie) { typeArguments = null; } } else if (expressionType.isGeneric()) { - typeArguments = null; + BaseType typeBound = contextualTypeBounds.get(expressionType.getName()); + + if (typeBound != null) { + getTypeArgumentVisitor.init(); + typeBound.accept(getTypeArgumentVisitor); + typeArguments = getTypeArgumentVisitor.getTypeArguments(); + } else { + typeArguments = null; + } } else { typeArguments = ((ObjectType)expressionType).getTypeArguments(); } @@ -535,10 +545,8 @@ public void visit(MethodInvocationExpression expression) { @Override public void visit(LocalVariableReferenceExpression expression) { - if (!type.isPrimitive()) { - AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); - localVariable.typeOnLeft(contextualTypeBounds, checkTypeArguments(type, localVariable)); - } + AbstractLocalVariable localVariable = ((ClassFileLocalVariableReferenceExpression) expression).getLocalVariable(); + localVariable.typeOnLeft(contextualTypeBounds, checkTypeArguments(type, localVariable)); } @Override @@ -593,6 +601,10 @@ public void visit(TernaryOperatorExpression expression) { @Override public void visit(BinaryOperatorExpression expression) { + if ((expression.getType() == TYPE_STRING) && "+".equals(expression.getOperator())) { + type = TYPE_OBJECT; + } + Type t = type; expression.getLeftExpression().accept(this); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java index 9e972d1a..6f78d7db 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/AddCastExpressionVisitor.java @@ -360,13 +360,20 @@ private Expression updateExpression(Type type, Expression expression, boolean fo ObjectType objectType = (ObjectType) type; ObjectType expressionObjectType = (ObjectType) expressionType; - if (!typeMaker.isAssignable(typeBounds, objectType, expressionObjectType)) { + if (force && !objectType.getInternalName().equals(expressionObjectType.getInternalName())) { + // Force disambiguation of method invocation => Uses raw type + if (expression.getClass() == ClassFileNewExpression.class) { + ClassFileNewExpression ne = (ClassFileNewExpression)expression; + ne.setObjectType(ne.getObjectType().createType(null)); + } + expression = addCastExpression(objectType, expression); + } else if (!typeMaker.isAssignable(typeBounds, objectType, expressionObjectType)) { BaseTypeArgument ta1 = objectType.getTypeArguments(); BaseTypeArgument ta2 = expressionObjectType.getTypeArguments(); Type t = type; if ((ta1 != null) && (ta2 != null) && !ta1.isTypeArgumentAssignableFrom(typeBounds, ta2)) { - // Incompatible typeArgument arguments => Uses raw typeArgument + // Incompatible typeArgument arguments => Uses raw type t = objectType.createType(null); } expression = addCastExpression(t, expression); @@ -381,7 +388,7 @@ private Expression updateExpression(Type type, Expression expression, boolean fo } } - if (expression.getClass() == CastExpression.class) { + if (!force && (expression.getClass() == CastExpression.class)) { CastExpression ce = (CastExpression)expression; Type ceExpressionType = ce.getExpression().getType(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java index 65121972..2d13449b 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java @@ -9,10 +9,10 @@ import org.jd.core.v1.model.classfile.ClassFile; import org.jd.core.v1.model.classfile.Method; +import org.jd.core.v1.model.classfile.attribute.AttributeCode; import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.statement.ByteCodeStatement; -import org.jd.core.v1.model.javasyntax.type.ObjectType; import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.cfg.ControlFlowGraph; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileBodyDeclaration; @@ -137,7 +137,14 @@ protected void createParametersVariablesAndStatements(ClassFileConstructorOrMeth comd.setFlags(comd.getFlags() & ~(FLAG_PUBLIC|FLAG_ABSTRACT)); } - localVariableMaker.make(); + boolean containsLineNumber = false; + AttributeCode attributeCode = method.getAttribute("Code"); + + if (attributeCode != null) { + containsLineNumber = (attributeCode.getAttribute("LineNumberTable") != null); + } + + localVariableMaker.make(containsLineNumber); comd.setFormalParameters(localVariableMaker.getFormalParameters()); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GetTypeArgumentVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GetTypeArgumentVisitor.java new file mode 100644 index 00000000..de0eb752 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/GetTypeArgumentVisitor.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.type.*; + +public class GetTypeArgumentVisitor implements TypeVisitor { + protected BaseTypeArgument typeArguments; + + public void init() { + this.typeArguments = null; + } + + public BaseTypeArgument getTypeArguments() { + return typeArguments; + } + + @Override public void visit(ObjectType type) { typeArguments = type.getTypeArguments(); } + @Override public void visit(InnerObjectType type) { typeArguments = type.getTypeArguments(); } + + @Override public void visit(PrimitiveType type) { typeArguments = null; } + @Override public void visit(GenericType type) { typeArguments = null; } + @Override public void visit(Types types) { typeArguments = null; } +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java index ddb7e73a..a5a1cc38 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitStaticFieldVisitor.java @@ -23,14 +23,14 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileStaticInitializerDeclaration; import org.jd.core.v1.util.DefaultList; -import java.util.Iterator; +import java.util.HashMap; import java.util.List; public class InitStaticFieldVisitor extends AbstractJavaSyntaxVisitor { protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); protected SearchLocalVariableReferenceVisitor searchLocalVariableReferenceVisitor = new SearchLocalVariableReferenceVisitor(); protected String internalTypeName; - protected DefaultList fields = new DefaultList<>(); + protected HashMap fields = new HashMap<>(); protected List methods; protected Boolean deleteStaticDeclaration; @@ -94,7 +94,7 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(FieldDeclarator declaration) { - fields.add(declaration); + fields.put(declaration.getName(), declaration); } @Override @@ -115,78 +115,46 @@ public void visit(StaticInitializerDeclaration declaration) { if (statements != null) { if (statements.isList()) { + DefaultList list = statements.getList(); + // Multiple statements - if ((statements.size() > 0) && isAssertionsDisabled(statements.getFirst())) { + if ((list.size() > 0) && isAssertionsDisabledStatement(list.getFirst())) { // Remove assert initialization statement - statements.getList().removeFirst(); + list.removeFirst(); } - if (statements.size() > 0) { - DefaultList list = statements.getList(); - Iterator fieldDeclaratorIterator = fields.iterator(); -// int lastLineNumber = 0; - - for (int i=0, len=list.size(); i 0) { - // Split 'static' block - BaseStatement newStatements; - - if (i == 1) { - newStatements = list.removeFirst(); - } else { - List subList = list.subList(0, i); - newStatements = new Statements(subList); - subList.clear(); - } - - // Removes statements from original list - len -= newStatements.size(); - i = 0; - - addStaticInitializerDeclaration(sid, getFirstLineNumber(newStatements), newStatements); + for (int i=0, len=list.size(); i 0) { + // Split 'static' block + BaseStatement newStatements; + + if (i == 1) { + newStatements = list.removeFirst(); + } else { + List subList = list.subList(0, i); + newStatements = new Statements(subList); + subList.clear(); } - // Remove field initialization statement - list.remove(i--); - len--; -// TODO Fix problem with local variable declarations before split static block -// lastLineNumber = 0; -// } else { -// int newLineNumber = getFirstLineNumber(statement); -// -// if ((lastLineNumber > 0) && (newLineNumber > 0) && (lastLineNumber + 3 < newLineNumber)) { -// // Split 'static' block -// BaseStatement newStatements; -// -// if (i == 1) { -// newStatements = list.removeFirst(); -// } else { -// List subList = list.subList(0, i); -// newStatements = new Statements(subList); -// subList.clear(); -// } -// -// // Removes statements from original list -// len -= newStatements.size(); -// i = 0; -// -// addStaticInitializerDeclaration(sid, newLineNumber, newStatements); -// } -// -// lastLineNumber = newLineNumber; + // Removes statements from original list + len -= newStatements.size(); + i = 0; + + addStaticInitializerDeclaration(sid, getFirstLineNumber(newStatements), newStatements); } + // Remove field initialization statement + list.remove(i--); + len--; } } } else { // Single statement - if (isAssertionsDisabled(statements.getFirst())) { + if (isAssertionsDisabledStatement(statements.getFirst())) { // Remove assert initialization statement statements = null; } - if ((statements != null) && setStaticFieldInitializer(statements.getFirst(), fields.iterator())) { + if ((statements != null) && setStaticFieldInitializer(statements.getFirst())) { // Remove field initialization statement statements = null; } @@ -202,7 +170,7 @@ public void visit(StaticInitializerDeclaration declaration) { } } - protected boolean isAssertionsDisabled(Statement statement) { + protected boolean isAssertionsDisabledStatement(Statement statement) { if ((statement.getClass() == ExpressionStatement.class)) { ExpressionStatement cdes = (ExpressionStatement) statement; @@ -222,7 +190,7 @@ protected boolean isAssertionsDisabled(Statement statement) { return false; } - protected boolean setStaticFieldInitializer(Statement statement, Iterator fieldDeclaratorIterator) { + protected boolean setStaticFieldInitializer(Statement statement) { if (statement.getClass() == ExpressionStatement.class) { ExpressionStatement cdes = (ExpressionStatement) statement; @@ -233,24 +201,22 @@ protected boolean setStaticFieldInitializer(Statement statement, Iterator nameMapping; + + public void init(HashMap nameMapping) { + this.nameMapping = nameMapping; + } + + @Override + public void visit(LocalVariableReferenceExpression expression) { + ClassFileLocalVariableReferenceExpression lvre = (ClassFileLocalVariableReferenceExpression)expression; + String newName = nameMapping.get(lvre.getName()); + + if (newName != null) { + lvre.getLocalVariable().setName(newName); + } + } + + @Override public void visit(FloatConstantExpression expression) {} + @Override public void visit(IntegerConstantExpression expression) {} + @Override public void visit(ConstructorReferenceExpression expression) {} + @Override public void visit(DoubleConstantExpression expression) {} + @Override public void visit(EnumConstantReferenceExpression expression) {} + @Override public void visit(LongConstantExpression expression) {} + @Override public void visit(BreakStatement statement) {} + @Override public void visit(ByteCodeStatement statement) {} + @Override public void visit(ContinueStatement statement) {} + @Override public void visit(NullExpression expression) {} + @Override public void visit(ObjectTypeReferenceExpression expression) {} + @Override public void visit(SuperExpression expression) {} + @Override public void visit(ThisExpression expression) {} + @Override public void visit(TypeReferenceDotClassExpression expression) {} + @Override public void visit(ObjectReference reference) {} + @Override public void visit(InnerObjectReference reference) {} + @Override public void visit(TypeArguments type) {} + @Override public void visit(WildcardExtendsTypeArgument type) {} + @Override public void visit(ObjectType type) {} + @Override public void visit(InnerObjectType type) {} + @Override public void visit(WildcardSuperTypeArgument type) {} + @Override public void visit(Types types) {} + @Override public void visit(TypeParameterWithTypeBounds type) {} +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchUndeclaredLocalVariableVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchUndeclaredLocalVariableVisitor.java index 76755de8..c2c411ed 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchUndeclaredLocalVariableVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchUndeclaredLocalVariableVisitor.java @@ -17,21 +17,15 @@ public class SearchUndeclaredLocalVariableVisitor extends AbstractJavaSyntaxVisitor { protected HashSet variables = new HashSet<>(); - protected boolean containsLineNumber; public void init() { variables.clear(); - containsLineNumber = false; } public HashSet getVariables() { return variables; } - public boolean containsLineNumber() { - return containsLineNumber; - } - @Override public void visit(BinaryOperatorExpression expression) { if ((expression.getLeftExpression().getClass() == ClassFileLocalVariableReferenceExpression.class) && (expression.getOperator().equals("="))) { @@ -51,12 +45,6 @@ public void visit(DoWhileStatement statement) { safeAccept(statement.getCondition()); } - @Override - public void visit(ExpressionStatement statement) { - containsLineNumber |= (statement.getExpression().getLineNumber() > 0); - statement.getExpression().accept(this); - } - @Override public void visit(ForEachStatement statement) { statement.getExpression().accept(this); @@ -82,7 +70,6 @@ public void visit(IfElseStatement statement) { @Override public void visit(LambdaExpressionStatement statement) { - containsLineNumber |= (statement.getExpression().getLineNumber() > 0); statement.getExpression().accept(this); } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java index d01297f7..caa15c87 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/JavaSyntaxToJavaFragmentProcessor.java @@ -29,7 +29,7 @@ public void process(Message message) throws Exception { int majorVersion = message.getHeader("majorVersion"); CompilationUnit compilationUnit = message.getBody(); - SearchImportsVisitor importsVisitor = new SearchImportsVisitor(mainInternalTypeName); + SearchImportsVisitor importsVisitor = new SearchImportsVisitor(loader, mainInternalTypeName); importsVisitor.visit(compilationUnit); ImportsFragment importsFragment = importsVisitor.getImportsFragment(); message.setHeader("maxLineNumber", importsVisitor.getMaxLineNumber()); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java index a1285658..e72c0143 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/SearchImportsVisitor.java @@ -7,6 +7,7 @@ package org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.visitor; +import org.jd.core.v1.api.loader.Loader; import org.jd.core.v1.model.javafragment.ImportsFragment; import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; import org.jd.core.v1.model.javasyntax.CompilationUnit; @@ -21,14 +22,16 @@ import java.util.HashSet; public class SearchImportsVisitor extends AbstractJavaSyntaxVisitor { + protected Loader loader; protected String internalPackagePrefix; protected ImportsFragment importsFragment = JavaFragmentFactory.newImportsFragment(); protected int maxLineNumber = 0; - protected HashSet typeNames = new HashSet<>(); + protected HashSet localTypeNames = new HashSet<>(); protected HashSet internalTypeNames = new HashSet<>(); protected HashSet importTypeNames = new HashSet<>(); - public SearchImportsVisitor(String mainInternalName) { + public SearchImportsVisitor(Loader loader, String mainInternalName) { + this.loader = loader; int index = mainInternalName.lastIndexOf('/'); this.internalPackagePrefix = (index == -1) ? "" : mainInternalName.substring(0, index + 1); } @@ -43,7 +46,7 @@ public int getMaxLineNumber() { } public void visit(CompilationUnit compilationUnit) { - compilationUnit.getTypeDeclarations().accept(new TypeVisitor(typeNames)); + compilationUnit.getTypeDeclarations().accept(new TypeVisitor(localTypeNames)); compilationUnit.getTypeDeclarations().accept(this); } @@ -289,11 +292,11 @@ protected void add(ObjectType type) { importTypeNames.add(typeName); } } else if (internalTypeName.startsWith(internalPackagePrefix)) { - if ((internalTypeName.indexOf('/', internalPackagePrefix.length()) != -1) && !typeNames.contains(typeName)) { + if ((internalTypeName.indexOf('/', internalPackagePrefix.length()) != -1) && !localTypeNames.contains(typeName)) { importsFragment.addImport(internalTypeName, type.getQualifiedName()); importTypeNames.add(typeName); } - } else if (!typeNames.contains(typeName)) { + } else if (!localTypeNames.contains(typeName) && !loader.canLoad(internalPackagePrefix + typeName)) { importsFragment.addImport(internalTypeName, type.getQualifiedName()); importTypeNames.add(typeName); } diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index a56bdb49..50f1cca4 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -23,7 +23,9 @@ import org.jd.core.v1.regex.PatternMaker; import org.junit.Test; +import java.io.FileInputStream; import java.io.InputStream; +import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -2597,7 +2599,7 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 61 */", "Supplier constructorReference = String::new;"))); assertTrue(source.matches(PatternMaker.make(": 65 */", "MethodType mtToString = MethodType.methodType(String.class);"))); assertTrue(source.matches(PatternMaker.make(": 66 */", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); - assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); assertTrue(source.indexOf("// Byte code:") == -1); @@ -2658,6 +2660,45 @@ public void testJdk901InterfaceWithDefaultMethods() throws Exception { } } + @Test + public void testBstMutationResult() throws Exception { + String internalClassName = "com/google/common/collect/BstMutationResult"; + Class mainClass = com.google.common.collect.Collections2.class; + InputStream is = new FileInputStream(Paths.get(mainClass.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile()); + Loader loader = new ZipLoader(is); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", internalClassName); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + // Check decompiled source code + assertTrue(source.indexOf("N resultLeft, resultRight;") != -1); + assertTrue(source.indexOf("assert false;") == -1); + assertTrue(source.matches(PatternMaker.make("/* 131:", "resultLeft = liftOriginalRoot.childOrNull(BstSide.LEFT);"))); + assertTrue(source.matches(PatternMaker.make("/* 134:", "case LEFT:"))); + + assertTrue(source.indexOf("// Byte code:") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + protected void printSource(String source) { System.out.println("- - - - - - - - "); System.out.println(source); diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 60c4a6fa..35d3a422 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -38,7 +38,7 @@ public class JarFileToJavaSourceTest extends TestCase { @Test public void testCommonsCodec() throws Exception { - // Decompile and recompile 'commons-codec-1.13.jar' + // Decompile and recompile 'commons-codec:commons-codec:1.13' test(org.apache.commons.codec.Charsets.class); } @@ -48,18 +48,43 @@ public void testCommonsCollections4() throws Exception { test(org.apache.commons.collections4.CollectionUtils.class); } + @Test + public void testCommonsImaging() throws Exception { + // Decompile and recompile 'org.apache.commons:commons-imaging:1.0-alpha1' + test(org.apache.commons.collections4.CollectionUtils.class); + } + @Test public void testCommonsLang3() throws Exception { - // Decompile and recompile 'commons-lang3-3.9.jar' + // Decompile and recompile 'org.apache.commons:commons-lang3:3.9' test(org.apache.commons.lang3.JavaVersion.class); } + @Test + public void testDiskLruCache() throws Exception { + // Decompile and recompile 'com.jakewharton:disklrucache:2.0.2' + test(com.jakewharton.disklrucache.DiskLruCache.class); + } + @Test public void testJavaPoet() throws Exception { // Decompile and recompile 'com.squareup:javapoet:1.11.1' test(com.squareup.javapoet.JavaFile.class); } + @Test + public void testJavaWriter() throws Exception { + // Decompile and recompile 'com.squareup:javawriter:2.5.1' + test(com.squareup.javawriter.JavaWriter.class); + } + + // TODO In progress + @Test + public void testJodaTime() throws Exception { + // Decompile and recompile 'joda-time:joda-time:2.10.5' + test(org.joda.time.DateTime.class); + } + @Test public void testJSoup() throws Exception { // Decompile and recompile 'org.jsoup:jsoup:1.12.1' @@ -72,12 +97,37 @@ public void testJUnit4() throws Exception { test(org.junit.Test.class); } + @Test + public void testMimecraft() throws Exception { + // Decompile and recompile 'com.squareup.mimecraft:mimecraft:1.1.1' + test(com.squareup.mimecraft.Part.class); + } + + @Test + public void testScribe() throws Exception { + // Decompile and recompile 'org.scribe:scribe:1.3.7' + test(org.scribe.oauth.OAuthService.class); + } + + @Test + public void testSparkCore() throws Exception { + // Decompile and recompile 'com.sparkjava:spark-core:2.9.1' + test(spark.Spark.class); + } + // TODO In progress -// @Test -// public void testLog4j() throws Exception { -// // Decompile and recompile 'log4j:log4j:1.2.17' -// test(org.apache.log4j.Category.class); -// } + @Test + public void testLog4j() throws Exception { + // Decompile and recompile 'log4j:log4j:1.2.17' + test(org.apache.log4j.Category.class); + } + + // TODO In progress + @Test + public void testGuava() throws Exception { + // Decompile and recompile 'com.google.guava:guava:12.0' + test(com.google.common.collect.Collections2.class); + } protected void test(Class clazz) throws Exception { test(new FileInputStream(Paths.get(clazz.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile())); @@ -176,6 +226,7 @@ protected void test(InputStream inputStream) throws Exception { assertTrue(exceptionCounter == 0); assertTrue(assertFailedCounter == 0); + assertTrue(printer.errorInMethodCounter == 0); assertTrue(recompilationFailedCounter == 0); } } diff --git a/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java b/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java index 5597f48b..11000599 100644 --- a/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java +++ b/src/test/java/org/jd/core/v1/cfg/ControlFlowGraphPlantUMLWriter.java @@ -140,6 +140,7 @@ protected static void search(HashSet set, BasicBlock basicBlock) { search(set, basicBlock.getNext()); case TYPE_CONDITION_TERNARY_OPERATOR: search(set, basicBlock.getCondition()); + case TYPE_CONDITION: case TYPE_CONDITION_OR: case TYPE_CONDITION_AND: search(set, basicBlock.getSub1()); @@ -325,6 +326,9 @@ protected static void writeLink(StringBuilder sb, BasicBlock basicBlock) { case TYPE_GOTO_IN_TERNARY_OPERATOR: writeLink(sb, id, basicBlock.getNext(), "next"); break; + case TYPE_CONDITION: + writeLink(sb, id, basicBlock.getSub1(), "sub1"); + writeLink(sb, id, basicBlock.getSub2(), "sub2"); case TYPE_CONDITIONAL_BRANCH: writeLink(sb, id, basicBlock.getNext(), "next"); writeLink(sb, id, basicBlock.getBranch(), "branch"); From 7c320beacfb7f4fddec5dd1b312269f6c7ca2b29 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 20 Jan 2020 19:48:30 +0100 Subject: [PATCH 155/211] Fix syntax errors in decompiled sources --- .../util/ByteCodeParser.java | 313 ++++++++++++++---- .../util/ControlFlowGraphReducer.java | 4 +- 2 files changed, 242 insertions(+), 75 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 8ab0c9e4..8d07bad9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -2489,91 +2489,258 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock return depth; } - public static int getOperandCount(BasicBlock bb) { + public static int getMinDepth(BasicBlock bb) { Method method = bb.getControlFlowGraph().getMethod(); ConstantPool constants = method.getConstants(); AttributeCode attributeCode = method.getAttribute("Code"); byte[] code = attributeCode.getCode(); - return getOperandCount(constants, code, bb); + return getMinDepth(constants, code, bb); } - private static int getOperandCount(ConstantPool constants, byte[] code, BasicBlock bb) { + private static int getMinDepth(ConstantPool constants, byte[] code, BasicBlock bb) { ConstantMemberRef constantMemberRef; ConstantNameAndType constantNameAndType; String descriptor; - int offset = bb.getFromOffset(); - int opcode = code[offset] & 255; + int depth = 0; + int minDepth = 0; - switch (opcode) { - case 89: // DUP - case 59: case 60: case 61: case 62: // ISTORE_0 ... ISTORE_3 - case 63: case 64: case 65: case 66: // LSTORE_0 ... LSTORE_3 - case 67: case 68: case 69: case 70: // FSTORE_0 ... FSTORE_3 - case 71: case 72: case 73: case 74: // DSTORE_0 ... DSTORE_3 - case 75: case 76: case 77: case 78: // ASTORE_0 ... ASTORE_3 - case 87: // POP - case 172: case 173: case 174: case 175: case 176: // IRETURN, LRETURN, FRETURN, DRETURN, ARETURN - case 194: case 195: // MONITORENTER, MONITOREXIT - case 153: case 154: case 155: case 156: case 157: case 158: // IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE - case 179: // PUTSTATIC - case 198: case 199: // IFNULL, IFNONNULL - case 54: case 55: case 56: case 57: case 58: // ISTORE, LSTORE, FSTORE, DSTORE, ASTORE - case 180: // GETFIELD - case 189: // ANEWARRAY - case 192: // CHECKCAST - case 193: // INSTANCEOF - case 188: // NEWARRAY - case 170: // TABLESWITCH - case 171: // LOOKUPSWITCH - return 1; - case 90: // DUP_X1 - case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: // IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD - case 96: case 97: case 98: case 99: // IADD, LADD, FADD, DADD - case 100: case 101: case 102: case 103: // ISUB, LSUB, FSUB, DSUB - case 104: case 105: case 106: case 107: // IMUL, LMUL, FMUL, DMUL - case 108: case 109: case 110: case 111: // IDIV, LDIV, FDIV, DDIV - case 112: case 113: case 114: case 115: // IREM, LREM, FREM, DREM - case 120: case 121: // ISHL, LSHL - case 122: case 123: // ISHR, LSHR - case 124: case 125: // IUSHR, LUSHR - case 126: case 127: // IAND, LAND - case 128: case 129: // IOR, LOR - case 130: case 131: // IXOR, LXOR - case 148: case 149: case 150: case 151: case 152: // LCMP, FCMPL, FCMPG, DCMPL, DCMPG - case 92: // DUP2 - case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: // IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE - case 181: // PUTFIELD - case 88: // POP2 - return 2; - case 91: // DUP_X2 - case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: // IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE - case 93: // DUP2_X1 - return 3; - case 94: // DUP2_X2 - return 4; - case 182: case 183: case 185: // INVOKEVIRTUAL, INVOKESPECIAL, INVOKEINTERFACE - constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); - constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - return 1 + countMethodParameters(descriptor); - case 184: case 186: // INVOKESTATIC, INVOKEDYNAMIC - constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); - constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); - return countMethodParameters(descriptor); - case 196: // WIDE - opcode = code[++offset] & 255; - switch (opcode) { - case 54: case 55: case 56: case 57: case 58: // ISTORE, LSTORE, FSTORE, DSTORE, ASTORE - return 1; - } - break; - case 197: // MULTIANEWARRAY - offset += 3; - return (code[offset] & 255); + for (int offset=bb.getFromOffset(), toOffset=bb.getToOffset(); offset depth) minDepth = depth; + depth += 2; + break; + case 90: // DUP_X1 + depth -= 2; + if (minDepth > depth) minDepth = depth; + depth += 3; + break; + case 91: // DUP_X2 + depth -= 3; + if (minDepth > depth) minDepth = depth; + depth += 4; + break; + case 16: case 18: // BIPUSH, LDC + case 21: case 22: case 23: case 24: case 25: // ILOAD, LLOAD, FLOAD, DLOAD, ALOAD + offset++; + depth++; + break; + case 17: // SIPUSH + case 19: case 20: // LDC_W, LDC2_W + case 168: // JSR + case 178: // GETSTATIC + case 187: // NEW + offset += 2; + depth++; + break; + case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: // IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD + case 96: case 97: case 98: case 99: // IADD, LADD, FADD, DADD + case 100: case 101: case 102: case 103: // ISUB, LSUB, FSUB, DSUB + case 104: case 105: case 106: case 107: // IMUL, LMUL, FMUL, DMUL + case 108: case 109: case 110: case 111: // IDIV, LDIV, FDIV, DDIV + case 112: case 113: case 114: case 115: // IREM, LREM, FREM, DREM + case 120: case 121: // ISHL, LSHL + case 122: case 123: // ISHR, LSHR + case 124: case 125: // IUSHR, LUSHR + case 126: case 127: // IAND, LAND + case 128: case 129: // IOR, LOR + case 130: case 131: // IXOR, LXOR + case 148: case 149: case 150: case 151: case 152: // LCMP, FCMPL, FCMPG, DCMPL, DCMPG + depth -= 2; + if (minDepth > depth) minDepth = depth; + depth++; + break; + case 59: case 60: case 61: case 62: // ISTORE_0 ... ISTORE_3 + case 63: case 64: case 65: case 66: // LSTORE_0 ... LSTORE_3 + case 67: case 68: case 69: case 70: // FSTORE_0 ... FSTORE_3 + case 71: case 72: case 73: case 74: // DSTORE_0 ... DSTORE_3 + case 75: case 76: case 77: case 78: // ASTORE_0 ... ASTORE_3 + case 87: // POP + case 172: case 173: case 174: case 175: case 176: // IRETURN, LRETURN, FRETURN, DRETURN, ARETURN + case 194: case 195: // MONITORENTER, MONITOREXIT + depth--; + if (minDepth > depth) minDepth = depth; + break; + case 153: case 154: case 155: case 156: case 157: case 158: // IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE + case 179: // PUTSTATIC + case 198: case 199: // IFNULL, IFNONNULL + offset += 2; + depth--; + if (minDepth > depth) minDepth = depth; + break; + case 54: case 55: case 56: case 57: case 58: // ISTORE, LSTORE, FSTORE, DSTORE, ASTORE + offset++; + depth--; + if (minDepth > depth) minDepth = depth; + break; + case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: // IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE + depth -= 3; + if (minDepth > depth) minDepth = depth; + break; + case 92: // DUP2 + depth -= 2; + if (minDepth > depth) minDepth = depth; + depth += 4; + break; + case 93: // DUP2_X1 + depth -= 3; + if (minDepth > depth) minDepth = depth; + depth += 5; + break; + case 94: // DUP2_X2 + depth -= 4; + if (minDepth > depth) minDepth = depth; + depth += 6; + break; + case 132: // IINC + case 167: // GOTO + offset += 2; + break; + case 180: // GETFIELD + case 189: // ANEWARRAY + case 192: // CHECKCAST + case 193: // INSTANCEOF + offset += 2; + depth--; + if (minDepth > depth) minDepth = depth; + depth++; + break; + case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: // IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE + case 181: // PUTFIELD + offset += 2; + depth -= 2; + if (minDepth > depth) minDepth = depth; + break; + case 88: // POP2 + depth -= 2; + if (minDepth > depth) minDepth = depth; + break; + case 169: // RET + offset++; + break; + case 188: // NEWARRAY + offset++; + depth--; + if (minDepth > depth) minDepth = depth; + depth++; + break; + case 170: // TABLESWITCH + offset = (offset + 4) & 0xFFFC; // Skip padding + offset += 4; // Skip default offset + + int low = ((code[offset++] & 255) << 24) | ((code[offset++] & 255) << 16) | ((code[offset++] & 255) << 8) | (code[offset++] & 255); + int high = ((code[offset++] & 255) << 24) | ((code[offset++] & 255) << 16) | ((code[offset++] & 255) << 8) | (code[offset++] & 255); + + offset += (4 * (high - low + 1)) - 1; + depth--; + if (minDepth > depth) minDepth = depth; + break; + case 171: // LOOKUPSWITCH + offset = (offset + 4) & 0xFFFC; // Skip padding + offset += 4; // Skip default offset + + int count = ((code[offset++] & 255) << 24) | ((code[offset++] & 255) << 16) | ((code[offset++] & 255) << 8) | (code[offset++] & 255); + + offset += (8 * count) - 1; + depth--; + if (minDepth > depth) minDepth = depth; + break; + case 182: case 183: // INVOKEVIRTUAL, INVOKESPECIAL + constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); + constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); + depth -= 1 + countMethodParameters(descriptor); + if (minDepth > depth) minDepth = depth; + + if (descriptor.charAt(descriptor.length()-1) != 'V') { + depth++; + } + break; + case 184: // INVOKESTATIC + constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); + constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); + depth -= countMethodParameters(descriptor); + if (minDepth > depth) minDepth = depth; + + if (descriptor.charAt(descriptor.length()-1) != 'V') { + depth++; + } + break; + case 185: // INVOKEINTERFACE + constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); + constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); + depth -= 1 + countMethodParameters(descriptor); + if (minDepth > depth) minDepth = depth; + offset += 2; // Skip 'count' and one byte + + if (descriptor.charAt(descriptor.length()-1) != 'V') { + depth++; + } + break; + case 186: // INVOKEDYNAMIC + constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); + constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); + depth -= countMethodParameters(descriptor); + if (minDepth > depth) minDepth = depth; + offset += 2; // Skip 2 bytes + + if (descriptor.charAt(descriptor.length()-1) != 'V') { + depth++; + } + break; + case 196: // WIDE + opcode = code[++offset] & 255; + + if (opcode == 132) { // IINC + offset += 4; + } else { + offset += 2; + + switch (opcode) { + case 21: case 22: case 23: case 24: case 25: // ILOAD, LLOAD, FLOAD, DLOAD, ALOAD + depth++; + break; + case 54: case 55: case 56: case 57: case 58: // ISTORE, LSTORE, FSTORE, DSTORE, ASTORE + depth--; + if (minDepth > depth) minDepth = depth; + break; + case 169: // RET + break; + } + } + break; + case 197: // MULTIANEWARRAY + offset += 3; + depth -= (code[offset] & 255); + if (minDepth > depth) minDepth = depth; + depth++; + break; + case 201: // JSR_W + offset += 4; + depth++; + case 200: // GOTO_W + offset += 4; + break; + } } - return 0; + return minDepth; } private static int countMethodParameters(String descriptor) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java index 7808162d..e5118b23 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphReducer.java @@ -279,7 +279,7 @@ protected static boolean aggregateConditionalBranches(BasicBlock basicBlock) { if (nextNext.matchType(TYPE_CONDITIONAL_BRANCH|TYPE_CONDITION)) { if (branch.matchType(TYPE_STATEMENTS|TYPE_GOTO_IN_TERNARY_OPERATOR) && (nextNext == branch.getNext()) && (branch.getPredecessors().size() == 1) && (nextNext.getPredecessors().size() == 2)) { - if (ByteCodeParser.getOperandCount(nextNext) == 1) { + if (ByteCodeParser.getMinDepth(nextNext) == -1) { updateConditionTernaryOperator(basicBlock, nextNext); return true; } @@ -292,7 +292,7 @@ protected static boolean aggregateConditionalBranches(BasicBlock basicBlock) { if (nextNextNextNext.matchType(TYPE_CONDITIONAL_BRANCH|TYPE_CONDITION)) { if (nextNextBranch.matchType(TYPE_STATEMENTS|TYPE_GOTO_IN_TERNARY_OPERATOR) && (nextNextNextNext == nextNextBranch.getNext()) && (nextNextBranch.getPredecessors().size() == 1) && (nextNextNextNext.getPredecessors().size() == 2)) { - if (ByteCodeParser.getOperandCount(nextNextNextNext) == 2) { + if (ByteCodeParser.getMinDepth(nextNextNextNext) == -2) { updateCondition(basicBlock, nextNext, nextNextNextNext); return true; } From 8cd329d1e364aec63550a567185ff76f6c46f8f9 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 26 Jan 2020 19:46:52 +0100 Subject: [PATCH 156/211] Improve local variable declaration in 'for' statements --- ...sFileLocalVariableReferenceExpression.java | 8 +- .../localvariable/AbstractLocalVariable.java | 4 + .../model/localvariable/Frame.java | 148 ++++++++++++++++-- .../model/localvariable/RootFrame.java | 12 ++ .../util/ByteCodeParser.java | 66 ++++---- .../util/LocalVariableMaker.java | 3 +- .../util/LoopStatementMaker.java | 12 ++ .../visitor/CreateInstructionsVisitor.java | 2 +- .../visitor/SearchFromOffsetVisitor.java | 50 ++++++ .../visitor/SearchLocalVariableVisitor.java | 50 ++++++ 10 files changed, 303 insertions(+), 52 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFromOffsetVisitor.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableVisitor.java diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java index 1a05ce35..f6db7b7a 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/expression/ClassFileLocalVariableReferenceExpression.java @@ -13,14 +13,20 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.LocalVariableReference; public class ClassFileLocalVariableReferenceExpression extends LocalVariableReferenceExpression implements LocalVariableReference { + protected int offset; protected AbstractLocalVariable localVariable; - public ClassFileLocalVariableReferenceExpression(int lineNumber, AbstractLocalVariable localVariable) { + public ClassFileLocalVariableReferenceExpression(int lineNumber, int offset, AbstractLocalVariable localVariable) { super(lineNumber, null, null); + this.offset = offset; this.localVariable = localVariable; localVariable.addReference(this); } + public int getOffset() { + return offset; + } + @Override public Type getType() { return localVariable.getType(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java index e3faed3a..ad7ed736 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/AbstractLocalVariable.java @@ -65,6 +65,10 @@ public void setToOffset(int offset) { this.toOffset = offset; } + public void setToOffset(int offset, boolean force) { + this.toOffset = offset; + } + public abstract Type getType(); public String getName() { return name; } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 8432aece..09b34d60 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -9,10 +9,7 @@ import org.jd.core.v1.model.javasyntax.declaration.*; import org.jd.core.v1.model.javasyntax.expression.*; -import org.jd.core.v1.model.javasyntax.statement.ExpressionStatement; -import org.jd.core.v1.model.javasyntax.statement.LocalVariableDeclarationStatement; -import org.jd.core.v1.model.javasyntax.statement.Statement; -import org.jd.core.v1.model.javasyntax.statement.Statements; +import org.jd.core.v1.model.javasyntax.statement.*; import org.jd.core.v1.model.javasyntax.type.*; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileConstructorInvocationExpression; import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; @@ -20,6 +17,9 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.statement.ClassFileForStatement; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.LocalVariableMaker; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.CreateLocalVariableVisitor; +import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchLocalVariableVisitor; import org.jd.core.v1.service.converter.classfiletojavasyntax.visitor.SearchUndeclaredLocalVariableVisitor; import org.jd.core.v1.util.DefaultList; @@ -270,6 +270,126 @@ public void createNames(HashSet parentNames) { } } + @SuppressWarnings("unchecked") + public void updateLocalVariableInForStatements(TypeMaker typeMaker) { + // Recursive call + if (children != null) { + for (Frame child : children) { + child.updateLocalVariableInForStatements(typeMaker); + } + } + + // Split local variable ranges in init 'for' statements + SearchLocalVariableVisitor searchLocalVariableVisitor = new SearchLocalVariableVisitor(); + HashSet undeclaredInExpressionStatements = new HashSet<>(); + + for (Statement statement : statements) { + Class statementClass = statement.getClass(); + + if (statementClass == ClassFileForStatement.class) { + ClassFileForStatement fs = (ClassFileForStatement) statement; + + if (fs.getInit() == null) { + if (fs.getCondition() != null) { + searchLocalVariableVisitor.init(); + fs.getCondition().accept(searchLocalVariableVisitor); + undeclaredInExpressionStatements.addAll(searchLocalVariableVisitor.getVariables()); + } + if (fs.getUpdate() != null) { + searchLocalVariableVisitor.init(); + fs.getUpdate().accept(searchLocalVariableVisitor); + undeclaredInExpressionStatements.addAll(searchLocalVariableVisitor.getVariables()); + } + if (fs.getStatements() != null) { + searchLocalVariableVisitor.init(); + fs.getStatements().accept(searchLocalVariableVisitor); + undeclaredInExpressionStatements.addAll(searchLocalVariableVisitor.getVariables()); + } + } + } else { + searchLocalVariableVisitor.init(); + statement.accept(searchLocalVariableVisitor); + undeclaredInExpressionStatements.addAll(searchLocalVariableVisitor.getVariables()); + } + } + + SearchUndeclaredLocalVariableVisitor searchUndeclaredLocalVariableVisitor = new SearchUndeclaredLocalVariableVisitor(); + HashMap> undeclaredInForStatements = new HashMap<>(); + + for (Statement statement : statements) { + Class statementClass = statement.getClass(); + + if (statementClass == ClassFileForStatement.class) { + ClassFileForStatement fs = (ClassFileForStatement) statement; + + if (fs.getInit() != null) { + searchUndeclaredLocalVariableVisitor.init(); + fs.getInit().accept(searchUndeclaredLocalVariableVisitor); + searchUndeclaredLocalVariableVisitor.getVariables().removeAll(undeclaredInExpressionStatements); + + for (AbstractLocalVariable lv : searchUndeclaredLocalVariableVisitor.getVariables()) { + List list = undeclaredInForStatements.get(lv); + if (list == null) { + undeclaredInForStatements.put(lv, list = new ArrayList<>()); + } + list.add(fs); + } + } + } + } + + if (!undeclaredInForStatements.isEmpty()) { + CreateLocalVariableVisitor createLocalVariableVisitor = new CreateLocalVariableVisitor(typeMaker); + + for (Map.Entry> entry : undeclaredInForStatements.entrySet()) { + List listFS = entry.getValue(); + + // Split local variable range + AbstractLocalVariable lv = entry.getKey(); + Iterator iteratorFS = listFS.iterator(); + ClassFileForStatement firstFS = iteratorFS.next(); + + while (iteratorFS.hasNext()) { + createNewLocalVariable(createLocalVariableVisitor, iteratorFS.next(), lv); + } + + if (lv.getFrame() == this) { + lv.setFromOffset(firstFS.getFromOffset()); + lv.setToOffset(firstFS.getToOffset(), true); + } else { + createNewLocalVariable(createLocalVariableVisitor, firstFS, lv); + + if (lv.getReferences().isEmpty()) { + lv.getFrame().removeLocalVariable(lv); + } + } + } + } + } + + protected void createNewLocalVariable(CreateLocalVariableVisitor createLocalVariableVisitor, ClassFileForStatement fs, AbstractLocalVariable lv) { + int fromOffset = fs.getFromOffset(), toOffset = fs.getToOffset(); + createLocalVariableVisitor.init(lv.getIndex(), fromOffset); + lv.accept(createLocalVariableVisitor); + AbstractLocalVariable newLV = createLocalVariableVisitor.getLocalVariable(); + + newLV.setToOffset(toOffset, true); + newLV.setName(lv.getName()); + addLocalVariable(newLV); + Iterator iteratorLVR = lv.getReferences().iterator(); + + while (iteratorLVR.hasNext()) { + LocalVariableReference lvr = iteratorLVR.next(); + int offset = ((ClassFileLocalVariableReferenceExpression) lvr).getOffset(); + + if ((fromOffset <= offset) && (offset <= toOffset)) { + lvr.setLocalVariable(newLV); + newLV.addReference(lvr); + iteratorLVR.remove(); + } + } + } + public void createDeclarations(boolean containsLineNumber) { // Create inline declarations createInlineDeclarations(); @@ -295,7 +415,7 @@ protected void createInlineDeclarations() { HashMap> map = createMapForInlineDeclarations(); if (!map.isEmpty()) { - SearchUndeclaredLocalVariableVisitor visitor = new SearchUndeclaredLocalVariableVisitor(); + SearchUndeclaredLocalVariableVisitor searchUndeclaredLocalVariableVisitor = new SearchUndeclaredLocalVariableVisitor(); for (Map.Entry> entry : map.entrySet()) { Statements statements = entry.getKey().statements; @@ -305,10 +425,10 @@ protected void createInlineDeclarations() { while (iterator.hasNext()) { Statement statement = iterator.next(); - visitor.init(); - statement.accept(visitor); + searchUndeclaredLocalVariableVisitor.init(); + statement.accept(searchUndeclaredLocalVariableVisitor); - HashSet undeclaredLocalVariablesInStatement = visitor.getVariables(); + HashSet undeclaredLocalVariablesInStatement = searchUndeclaredLocalVariableVisitor.getVariables(); undeclaredLocalVariablesInStatement.retainAll(undeclaredLocalVariables); if (!undeclaredLocalVariablesInStatement.isEmpty()) { @@ -363,15 +483,11 @@ protected HashMap> createMapForInlineDecla while (lv != null) { if ((this == lv.getFrame()) && !lv.isDeclared()) { - HashSet variablesToDeclare = map.get(lv.getFrame()); - + HashSet variablesToDeclare = map.get(this); if (variablesToDeclare == null) { - variablesToDeclare = new HashSet<>(); - variablesToDeclare.add(lv); - map.put(lv.getFrame(), variablesToDeclare); - } else { - variablesToDeclare.add(lv); + map.put(this, variablesToDeclare = new HashSet<>()); } + variablesToDeclare.add(lv); } lv = lv.getNext(); } @@ -533,7 +649,7 @@ protected void updateForStatement( Type type0 = null, type1 = null; int minDimension = 0, maxDimension = 0; - for (Expression expression : (List)init) { + for (Expression expression : init) { if (expression.getClass() != BinaryOperatorExpression.class) return; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java index 5a24e0c9..13be0ad4 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/RootFrame.java @@ -7,6 +7,8 @@ package org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable; +import org.jd.core.v1.service.converter.classfiletojavasyntax.util.TypeMaker; + public class RootFrame extends Frame { public RootFrame() { @@ -20,6 +22,16 @@ public AbstractLocalVariable getLocalVariable(int index) { return null; } + @Override + public void updateLocalVariableInForStatements(TypeMaker typeMaker) { + if (children != null) { + for (Frame child : children) { + child.updateLocalVariableInForStatements(typeMaker); + } + } + } + + @Override public void createDeclarations(boolean containsLineNumber) { if (children != null) { for (Frame child : children) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 8d07bad9..37167bd3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -141,11 +141,11 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack stack, ConstantPool constants, in } } - private static void parseILOAD(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable) { + private static void parseILOAD(Statements statements, DefaultStack stack, int lineNumber, int offset, AbstractLocalVariable localVariable) { if (! statements.isEmpty()) { Statement statement = statements.getLast(); @@ -1095,12 +1095,12 @@ private static void parseILOAD(Statements statements, DefaultStack s } } - stack.push(new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable)); + stack.push(new ClassFileLocalVariableReferenceExpression(lineNumber, offset, localVariable)); } @SuppressWarnings("unchecked") - private void parseSTORE(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { - ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); + private void parseSTORE(Statements statements, DefaultStack stack, int lineNumber, int offset, AbstractLocalVariable localVariable, Expression valueRef) { + ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, offset, localVariable); bindParameterTypesWithArgumentTypes(vre.getType(), valueRef); @@ -1479,11 +1479,11 @@ private static boolean isNegativeOne(Expression expression) { return ((expression.getClass() == DoubleConstantExpression.class) && ((DoubleConstantExpression)expression).getValue() == -1.0D); } - private void parseASTORE(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, Expression valueRef) { + private void parseASTORE(Statements statements, DefaultStack stack, int lineNumber, int offset, AbstractLocalVariable localVariable, Expression valueRef) { bindParameterTypesWithArgumentTypes(localVariable.getType(), valueRef); localVariable.typeOnRight(typeBounds, valueRef.getType()); - ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); + ClassFileLocalVariableReferenceExpression vre = new ClassFileLocalVariableReferenceExpression(lineNumber, offset, localVariable); Expression oldValueRef = valueRef; if (valueRef.getClass() == NewArray.class) { @@ -1584,7 +1584,7 @@ private void createAssignment(Statements statements, DefaultStack st } @SuppressWarnings("unchecked") - private void parseIINC(Statements statements, DefaultStack stack, int lineNumber, AbstractLocalVariable localVariable, int count) { + private void parseIINC(Statements statements, DefaultStack stack, int lineNumber, int offset, AbstractLocalVariable localVariable, int count) { Expression expression; if (!stack.isEmpty()) { @@ -1610,7 +1610,7 @@ private void parseIINC(Statements statements, DefaultStack stack, in } } - expression = new ClassFileLocalVariableReferenceExpression(lineNumber, localVariable); + expression = new ClassFileLocalVariableReferenceExpression(lineNumber, offset, localVariable); if (count == 1) { expression = newPreArithmeticOperatorExpression(lineNumber, "++", expression); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 1caa6109..9e52e7e9 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -493,8 +493,9 @@ public boolean containsName(String name) { return names.contains(name); } - public void make(boolean containsLineNumber) { + public void make(boolean containsLineNumber, TypeMaker typeMaker) { currentFrame.createNames(blackListNames); + currentFrame.updateLocalVariableInForStatements(typeMaker); currentFrame.createDeclarations(containsLineNumber); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java index bfead8cc..8161b3af 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LoopStatementMaker.java @@ -756,6 +756,18 @@ protected static Statement makeLabels(int loopIndex, int continueOffset, int bre protected static ClassFileForStatement newClassFileForStatement( LocalVariableMaker localVariableMaker, int fromOffset, int toOffset, BaseExpression init, Expression condition, BaseExpression update, BaseStatement statements) { + if (init != null) { + SearchFromOffsetVisitor visitor = new SearchFromOffsetVisitor(); + + init.accept(visitor); + + int offset = visitor.getOffset(); + + if (fromOffset > offset) { + fromOffset = offset; + } + } + ChangeFrameOfLocalVariablesVisitor visitor = new ChangeFrameOfLocalVariablesVisitor(localVariableMaker); if (condition != null) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java index 2d13449b..097f6d46 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/CreateInstructionsVisitor.java @@ -144,7 +144,7 @@ protected void createParametersVariablesAndStatements(ClassFileConstructorOrMeth containsLineNumber = (attributeCode.getAttribute("LineNumberTable") != null); } - localVariableMaker.make(containsLineNumber); + localVariableMaker.make(containsLineNumber, typeMaker); comd.setFormalParameters(localVariableMaker.getFormalParameters()); } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFromOffsetVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFromOffsetVisitor.java new file mode 100644 index 00000000..10294645 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchFromOffsetVisitor.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; + +public class SearchFromOffsetVisitor extends AbstractJavaSyntaxVisitor { + protected int offset; + + public SearchFromOffsetVisitor() { + offset = Integer.MAX_VALUE; + } + + public void init() { + offset = Integer.MAX_VALUE; + } + + public int getOffset() { + return this.offset; + } + + @Override + public void visit(LocalVariableReferenceExpression expression) { + int offset = ((ClassFileLocalVariableReferenceExpression) expression).getOffset(); + + if (this.offset > offset) { + this.offset = offset; + } + } + + @Override public void visit(IntegerConstantExpression expression) {} + + @Override public void visit(TypeArguments arguments) {} + @Override public void visit(DiamondTypeArgument argument) {} + @Override public void visit(WildcardExtendsTypeArgument argument) {} + @Override public void visit(WildcardSuperTypeArgument argument) {} + @Override public void visit(WildcardTypeArgument argument) {} + @Override public void visit(PrimitiveType type) {} + @Override public void visit(ObjectType type) {} + @Override public void visit(InnerObjectType type) {} + @Override public void visit(GenericType type) {} +} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableVisitor.java new file mode 100644 index 00000000..93fa13d3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/SearchLocalVariableVisitor.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.visitor; + +import org.jd.core.v1.model.javasyntax.AbstractJavaSyntaxVisitor; +import org.jd.core.v1.model.javasyntax.expression.IntegerConstantExpression; +import org.jd.core.v1.model.javasyntax.expression.LocalVariableReferenceExpression; +import org.jd.core.v1.model.javasyntax.type.*; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.expression.ClassFileLocalVariableReferenceExpression; +import org.jd.core.v1.service.converter.classfiletojavasyntax.model.localvariable.AbstractLocalVariable; + +import java.util.HashSet; + +public class SearchLocalVariableVisitor extends AbstractJavaSyntaxVisitor { + protected HashSet variables = new HashSet<>(); + + public void init() { + variables.clear(); + } + + public HashSet getVariables() { + return variables; + } + + @Override + public void visit(LocalVariableReferenceExpression expression) { + AbstractLocalVariable lv = ((ClassFileLocalVariableReferenceExpression)expression).getLocalVariable(); + + if (!lv.isDeclared()) { + variables.add(lv); + } + } + + @Override public void visit(IntegerConstantExpression expression) {} + + @Override public void visit(TypeArguments arguments) {} + @Override public void visit(DiamondTypeArgument argument) {} + @Override public void visit(WildcardExtendsTypeArgument argument) {} + @Override public void visit(WildcardSuperTypeArgument argument) {} + @Override public void visit(WildcardTypeArgument argument) {} + @Override public void visit(PrimitiveType type) {} + @Override public void visit(ObjectType type) {} + @Override public void visit(InnerObjectType type) {} + @Override public void visit(GenericType type) {} +} From dec587926cbe466c277b0d9b9370021f50b5337f Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 30 Jan 2020 07:57:15 +0100 Subject: [PATCH 157/211] Fix bug on instance initializer block --- .../declaration/ConstructorDeclaration.java | 4 + .../javasyntax/declaration/Declaration.java | 1 + .../ClassFileConstructorDeclaration.java | 5 - .../visitor/InitEnumVisitor.java | 28 ++-- .../visitor/InitInnerClassVisitor.java | 6 +- .../visitor/InitInstanceFieldVisitor.java | 2 +- .../RemoveDefaultConstructorVisitor.java | 18 ++- .../util/JavaFragmentFactory.java | 10 ++ .../visitor/CompilationUnitVisitor.java | 153 ++++++++++-------- .../jd/core/v1/ClassFileToJavaSourceTest.java | 38 +++++ 10 files changed, 167 insertions(+), 98 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java index 27f4d9c7..97b73e29 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ConstructorDeclaration.java @@ -42,6 +42,10 @@ public int getFlags() { return flags; } + public void setFlags(int flags) { + this.flags = flags; + } + public BaseAnnotationReference getAnnotationReferences() { return annotationReferences; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java index 8e545613..e6cfd0c9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/Declaration.java @@ -25,6 +25,7 @@ public interface Declaration { int FLAG_VARARGS = 0x0080; // . . M . . . . . int FLAG_NATIVE = 0x0100; // . . M . . . . . int FLAG_INTERFACE = 0x0200; // C . . N . . . . + int FLAG_ANONYMOUS = 0x0200; // . . M . . . . . // Custom flag int FLAG_ABSTRACT = 0x0400; // C . M N . . . . int FLAG_STRICT = 0x0800; // . . M . . . . . int FLAG_SYNTHETIC = 0x1000; // C F M N Mo MR ME MO diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java index fdb70f4f..dd7a055f 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/javasyntax/declaration/ClassFileConstructorDeclaration.java @@ -43,11 +43,6 @@ public ClassFileConstructorDeclaration( this.firstLineNumber = firstLineNumber; } - @Override - public void setFlags(int flags) { - this.flags = flags; - } - @Override public void setFormalParameters(BaseFormalParameter formalParameters) { this.formalParameters = formalParameters; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java index 9d80781e..210b5df3 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitEnumVisitor.java @@ -49,24 +49,18 @@ public void visit(BodyDeclaration declaration) { @Override public void visit(ConstructorDeclaration declaration) { - ClassFileConstructorDeclaration cfcd = (ClassFileConstructorDeclaration)declaration; - - if (cfcd.getStatements().getClass() == Statements.class) { - Statements statements = (Statements)cfcd.getStatements(); - - if (statements.size() == 1) { - cfcd.setFlags(FLAG_SYNTHETIC); - } else { - FormalParameters parameters = (FormalParameters)cfcd.getFormalParameters(); - // Remove name & index parameterTypes - parameters.subList(0, 2).clear(); - // Remove super constructor call - statements.remove(0); - // Fix flags - cfcd.setFlags(0); - } + if ((declaration.getFlags() & FLAG_ANONYMOUS) != 0) { + declaration.setFlags(FLAG_SYNTHETIC); + } else if (declaration.getStatements().size() <= 1) { + declaration.setFlags(FLAG_SYNTHETIC); } else { - cfcd.setFlags(FLAG_SYNTHETIC); + FormalParameters parameters = (FormalParameters)declaration.getFormalParameters(); + // Remove name & index parameterTypes + parameters.subList(0, 2).clear(); + // Remove super constructor call + declaration.getStatements().getList().remove(0); + // Fix flags + declaration.setFlags(0); } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java index 9ccb7fac..1131a134 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInnerClassVisitor.java @@ -156,7 +156,7 @@ public void visit(ConstructorDeclaration declaration) { } } - // Hide anonymous class constructor + // Anonymous class constructor ? if (outerClassFile != null) { String outerTypeName = outerClassFile.getInternalTypeName(); String internalTypeName = cfcd.getClassFile().getInternalTypeName(); @@ -180,8 +180,8 @@ public void visit(ConstructorDeclaration declaration) { } if (anonymousFlag) { - // Hide anonymous class constructor - cfcd.setFlags(cfcd.getFlags() | Constants.ACC_SYNTHETIC); + // Mark anonymous class constructor + cfcd.setFlags(cfcd.getFlags() | Declaration.FLAG_ANONYMOUS); } } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java index fc659d4c..94dbe3dd 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java @@ -82,7 +82,7 @@ public void visit(FieldDeclaration declaration) { public void visit(ConstructorDeclaration declaration) { ClassFileConstructorDeclaration cfcd = (ClassFileConstructorDeclaration)declaration; - if (cfcd.getStatements().getClass() == Statements.class) { + if ((cfcd.getStatements() != null) && (cfcd.getStatements().getClass() == Statements.class)) { Statements statements = (Statements) cfcd.getStatements(); ListIterator iterator = statements.listIterator(); SuperConstructorInvocationExpression superConstructorCall = searchSuperConstructorCall(iterator); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java index ce479c7b..525e9659 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/RemoveDefaultConstructorVisitor.java @@ -24,6 +24,8 @@ import java.util.Iterator; import java.util.List; +import static org.jd.core.v1.model.javasyntax.declaration.Declaration.FLAG_ANONYMOUS; + public class RemoveDefaultConstructorVisitor extends AbstractJavaSyntaxVisitor { protected int constructorCounter; protected ClassFileMemberDeclaration constructor; @@ -57,10 +59,10 @@ public void visit(ConstructorDeclaration declaration) { if ((declaration.getFlags() & ConstructorDeclaration.FLAG_ABSTRACT) == 0) { ClassFileConstructorDeclaration cfcd = (ClassFileConstructorDeclaration)declaration; - if (cfcd.getStatements().getClass() == Statements.class) { + if ((cfcd.getStatements() != null) && (cfcd.getStatements().getClass() == Statements.class)) { Statements statements = (Statements) cfcd.getStatements(); - // Remove 'super();' + // Remove no-parameter super constructor call and anonymous class super constructor call Iterator iterator = statements.iterator(); while (iterator.hasNext()) { @@ -71,9 +73,17 @@ public void visit(ConstructorDeclaration declaration) { if (es.getClass() == ClassFileSuperConstructorInvocationExpression.class) { SuperConstructorInvocationExpression scie = (SuperConstructorInvocationExpression) es; - BaseExpression parameters = scie.getParameters(); - if ((parameters == null) || (parameters.size() == 0)) { + if ((declaration.getFlags() & FLAG_ANONYMOUS) == 0) { + BaseExpression parameters = scie.getParameters(); + + if ((parameters == null) || (parameters.size() == 0)) { + // Remove 'super();' + iterator.remove(); + break; + } + } else { + // Remove anonymous class super constructor call iterator.remove(); break; } diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java index e509b9b1..2b90c9cd 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/util/JavaFragmentFactory.java @@ -43,6 +43,10 @@ public static void addEndMethodBody(List fragments, StartBodyFragment fragments.add(new EndBodyFragment(0, 1, 1, 8, "End method body", start)); } + public static void addEndInstanceInitializerBlock(List fragments, StartBlockFragment start) { + fragments.add(new EndBlockFragment(0, 1, 1, 8, "End anonymous method body", start)); + } + public static void addEndTypeBody(List fragments, StartBodyFragment start) { fragments.add(new EndBodyFragment(0, 1, 1, 3, "End type body", start)); } @@ -161,6 +165,12 @@ public static StartBodyFragment addStartMethodBody(List fragments) { return fragment; } + public static StartBlockFragment addStartInstanceInitializerBlock(List fragments) { + StartBlockFragment fragment = new StartBlockFragment(0, 1, 2, 9, "Start anonymous method body"); + fragments.add(fragment); + return fragment; + } + public static StartBodyFragment addStartTypeBody(List fragments) { StartBodyFragment fragment = new StartBodyFragment(0, 1, 2, 4, "Start type body"); fragments.add(fragment); diff --git a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java index 6c4f7163..4c341e8e 100644 --- a/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java +++ b/src/main/java/org/jd/core/v1/service/fragmenter/javasyntaxtojavafragment/visitor/CompilationUnitVisitor.java @@ -322,100 +322,117 @@ public void visit(CompilationUnit compilationUnit) { @Override public void visit(ConstructorDeclaration declaration) { if ((declaration.getFlags() & (FLAG_SYNTHETIC|FLAG_BRIDGE)) == 0) { - fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); - - tokens = new Tokens(); + BaseStatement statements = declaration.getStatements(); - // Build fragments for annotations - BaseAnnotationReference annotationReferences = declaration.getAnnotationReferences(); + if ((declaration.getFlags() & FLAG_ANONYMOUS) == 0) { + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); - if (annotationReferences != null) { - annotationReferences.accept(annotationVisitor); - fragments.addTokensFragment(tokens); - JavaFragmentFactory.addSpacerAfterMemberAnnotations(fragments); tokens = new Tokens(); - } - // Build tokens for access - buildTokensForMethodAccessFlags(declaration.getFlags()); + // Build fragments for annotations + BaseAnnotationReference annotationReferences = declaration.getAnnotationReferences(); - // Build tokens for type parameters - BaseTypeParameter typeParameters = declaration.getTypeParameters(); + if (annotationReferences != null) { + annotationReferences.accept(annotationVisitor); + fragments.addTokensFragment(tokens); + JavaFragmentFactory.addSpacerAfterMemberAnnotations(fragments); + tokens = new Tokens(); + } - if (typeParameters != null) { - tokens.add(TextToken.LEFTANGLEBRACKET); - typeParameters.accept(this); - tokens.add(TextToken.RIGHTANGLEBRACKET); - tokens.add(TextToken.SPACE); - } + // Build tokens for access + buildTokensForMethodAccessFlags(declaration.getFlags()); - // Build token for type declaration - tokens.add(new DeclarationToken(DeclarationToken.CONSTRUCTOR, currentInternalTypeName, currentTypeName, declaration.getDescriptor())); + // Build tokens for type parameters + BaseTypeParameter typeParameters = declaration.getTypeParameters(); - storeContext(); - currentMethodParamNames.clear(); + if (typeParameters != null) { + tokens.add(TextToken.LEFTANGLEBRACKET); + typeParameters.accept(this); + tokens.add(TextToken.RIGHTANGLEBRACKET); + tokens.add(TextToken.SPACE); + } - BaseFormalParameter formalParameters = declaration.getFormalParameters(); + // Build token for type declaration + tokens.add(new DeclarationToken(DeclarationToken.CONSTRUCTOR, currentInternalTypeName, currentTypeName, declaration.getDescriptor())); - if (formalParameters == null) { - tokens.add(TextToken.LEFTRIGHTROUNDBRACKETS); - } else { - tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); - fragments.addTokensFragment(tokens); + storeContext(); + currentMethodParamNames.clear(); - formalParameters.accept(this); + BaseFormalParameter formalParameters = declaration.getFormalParameters(); - tokens = new Tokens(); - tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); - } + if (formalParameters == null) { + tokens.add(TextToken.LEFTRIGHTROUNDBRACKETS); + } else { + tokens.add(StartBlockToken.START_PARAMETERS_BLOCK); + fragments.addTokensFragment(tokens); - BaseType exceptionTypes = declaration.getExceptionTypes(); + formalParameters.accept(this); - if (exceptionTypes != null) { - tokens.add(TextToken.SPACE); - tokens.add(THROWS); - tokens.add(TextToken.SPACE); - exceptionTypes.accept(this); - } + tokens = new Tokens(); + tokens.add(EndBlockToken.END_PARAMETERS_BLOCK); + } - BaseStatement statements = declaration.getStatements(); + BaseType exceptionTypes = declaration.getExceptionTypes(); - if (statements == null) { - tokens.add(TextToken.SEMICOLON); - fragments.addTokensFragment(tokens); - } else { - fragments.addTokensFragment(tokens); - singleLineStatementVisitor.init(); - statements.accept(singleLineStatementVisitor); + if (exceptionTypes != null) { + tokens.add(TextToken.SPACE); + tokens.add(THROWS); + tokens.add(TextToken.SPACE); + exceptionTypes.accept(this); + } - boolean singleLineStatement = singleLineStatementVisitor.isSingleLineStatement(); - int fragmentCount1 = fragments.size(); - StartBodyFragment start; + if (statements != null) { + fragments.addTokensFragment(tokens); + singleLineStatementVisitor.init(); + statements.accept(singleLineStatementVisitor); - if (singleLineStatement) { - start = JavaFragmentFactory.addStartSingleStatementMethodBody(fragments); - } else { - start = JavaFragmentFactory.addStartMethodBody(fragments); + boolean singleLineStatement = singleLineStatementVisitor.isSingleLineStatement(); + int fragmentCount1 = fragments.size(); + StartBodyFragment start; + + if (singleLineStatement) { + start = JavaFragmentFactory.addStartSingleStatementMethodBody(fragments); + } else { + start = JavaFragmentFactory.addStartMethodBody(fragments); + } + + int fragmentCount2 = fragments.size(); + + statements.accept(this); + + if (fragmentCount2 == fragments.size()) { + fragments.subList(fragmentCount1, fragmentCount2).clear(); + tokens.add(TextToken.SPACE); + tokens.add(TextToken.LEFTRIGHTCURLYBRACKETS); + } else if (singleLineStatement) { + JavaFragmentFactory.addEndSingleStatementMethodBody(fragments, start); + } else { + JavaFragmentFactory.addEndMethodBody(fragments, start); + } } + restoreContext(); + + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + } else if ((statements != null) && (statements.size() > 0)) { + int fragmentCount0 = fragments.size(); + fragments.add(StartMovableJavaBlockFragment.START_MOVABLE_METHOD_BLOCK); + + StartBlockFragment start = JavaFragmentFactory.addStartInstanceInitializerBlock(fragments); int fragmentCount2 = fragments.size(); + tokens = new Tokens(); + statements.accept(this); if (fragmentCount2 == fragments.size()) { - fragments.subList(fragmentCount1, fragmentCount2).clear(); - tokens.add(TextToken.SPACE); - tokens.add(TextToken.LEFTRIGHTCURLYBRACKETS); - } else if (singleLineStatement) { - JavaFragmentFactory.addEndSingleStatementMethodBody(fragments, start); + fragments.subList(fragmentCount0, fragmentCount2).clear(); } else { - JavaFragmentFactory.addEndMethodBody(fragments, start); + JavaFragmentFactory.addEndInstanceInitializerBlock(fragments, start); } - } - - fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); - restoreContext(); + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); + } } } @@ -1179,9 +1196,9 @@ public void visit(MethodDeclaration declaration) { } } - fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); - restoreContext(); + + fragments.add(EndMovableJavaBlockFragment.END_MOVABLE_BLOCK); } } diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 50f1cca4..c1362fc6 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -11,6 +11,7 @@ import org.jd.core.v1.api.loader.Loader; import org.jd.core.v1.compiler.CompilerUtil; import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; import org.jd.core.v1.loader.ZipLoader; import org.jd.core.v1.model.message.Message; import org.jd.core.v1.printer.PlainTextPrinter; @@ -1118,6 +1119,8 @@ public void testJdk150AnonymousClass() throws Exception { assertTrue(source.matches(PatternMaker.make(": 104 */", "System.out.println(\"end\");"))); assertTrue(source.indexOf("/* 111: 111 */") != -1); + + assertTrue(source.indexOf("{ ;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors @@ -2014,6 +2017,7 @@ public void testJdk170AnonymousClass() throws Exception { assertTrue(source.matches(PatternMaker.make(": 111 */", "this.l = l & 0x80L;"))); + assertTrue(source.indexOf("{ ;") == -1); assertTrue(source.indexOf("} ;") == -1); assertTrue(source.indexOf("// Byte code:") == -1); @@ -2699,6 +2703,40 @@ public void testBstMutationResult() throws Exception { assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } + @Test + public void testAnnotationUtils() throws Exception { + String internalClassName = "org/apache/commons/lang3/AnnotationUtils"; + Loader loader = new ClassPathLoader(); + //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); + PlainTextPrinter printer = new PlainTextPrinter(); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + + Message message = new Message(); + message.setHeader("mainInternalTypeName", internalClassName); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + // Check decompiled source code + assertTrue(source.indexOf("setDefaultFullDetail(true);") != -1); + + assertTrue(source.indexOf("// Byte code:") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + protected void printSource(String source) { System.out.println("- - - - - - - - "); System.out.println(source); From 9daa0e318fe9b480d03c847544e1cd74feaeb98e Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 30 Jan 2020 07:58:57 +0100 Subject: [PATCH 158/211] Update README.md --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 65682eda..64b0399d 100644 --- a/README.md +++ b/README.md @@ -112,8 +112,3 @@ String source = printer.toString(); ## License Released under the [GNU GPL v3](LICENSE). - -## Donations -Did JD-GUI help you to solve a critical situation? Do you use JD-Eclipse daily? What about making a donation? - -[![paypal](https://raw.githubusercontent.com/java-decompiler/jd-core/master/src/website/img/btn_donate_euro.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=C88ZMVZ78RF22) [![paypal](https://raw.githubusercontent.com/java-decompiler/jd-core/master/src/website/img/btn_donate_usd.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CRMXT4Y4QLQGU) From 821681a6f310aa377e6b0895177aaf61e089b2f2 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Thu, 30 Jan 2020 19:15:17 +0100 Subject: [PATCH 159/211] Minor updates --- .../EnumConstantReferenceExpression.java | 2 +- .../expression/FieldReferenceExpression.java | 2 +- .../LocalVariableReferenceExpression.java | 2 +- .../model/localvariable/Frame.java | 2 +- .../util/ControlFlowGraphMaker.java | 2 +- .../util/LocalVariableMaker.java | 2 +- .../util/MergeMembersUtil.java | 2 +- .../classfile/ClassFileDeserializer.java | 2 +- .../DeserializeClassFileProcessor.java | 2 +- .../jd/core/v1/AnnotationConverterTest.java | 2 +- .../jd/core/v1/JarFileToJavaSourceTest.java | 22 +++++++++---------- 11 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java index 458c1d63..f556ad2d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java @@ -46,6 +46,6 @@ public void accept(ExpressionVisitor visitor) { @Override public String toString() { - return "EnumConstantReferenceExpression{lastType=" + type + ", name=" + name + "}"; + return "EnumConstantReferenceExpression{type=" + type + ", name=" + name + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java index c48f65c8..5673b187 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java @@ -62,6 +62,6 @@ public void accept(ExpressionVisitor visitor) { @Override public String toString() { - return "FieldReferenceExpression{lastType=" + type + ", expression=" + expression + ", name=" + name + ", descriptor=" + descriptor + "}"; + return "FieldReferenceExpression{type=" + type + ", expression=" + expression + ", name=" + name + ", descriptor=" + descriptor + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java index 34db3bb6..62e926c4 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java @@ -33,6 +33,6 @@ public void accept(ExpressionVisitor visitor) { @Override public String toString() { - return "LocalVariableReferenceExpression{lastType=" + type + ", name=" + name + "}"; + return "LocalVariableReferenceExpression{type=" + type + ", name=" + name + "}"; } } diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java index 09b34d60..15a39ec1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/model/localvariable/Frame.java @@ -190,7 +190,7 @@ public void addChild(Frame child) { } public void close() { - // Update lastType for 'new' expression + // Update type for 'new' expression if (newExpressions != null) { for (Map.Entry entry : newExpressions.entrySet()) { ObjectType ot1 = entry.getKey().getObjectType(); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java index 4f20e897..4f0d61f0 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java @@ -372,7 +372,7 @@ public static ControlFlowGraph make(Method method) { map[lastOffset] = cfg.newBasicBlock(lastOffset, length); - // --- Set lastType, successors and predecessors --- // + // --- Set type, successors and predecessors --- // List list = cfg.getBasicBlocks(); List basicBlocks = new DefaultList<>(list.size()); BasicBlock successor = list.get(1); diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java index 9e52e7e9..371c9243 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/LocalVariableMaker.java @@ -249,7 +249,7 @@ protected void initLocalVariablesFromParameterTypes(ClassFile classFile, BaseTyp if ((parameterIndex == lastParameterIndex) && varargs) { sb.append("VarArgs"); -// } else if (lastType.getDimension() > 1) { +// } else if (type.getDimension() > 1) { // sb.append("ArrayOfArray"); } else { if (type.getDimension() > 0) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java index 9c4e3a16..13506503 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/MergeMembersUtil.java @@ -93,7 +93,7 @@ protected static void sort(List members) { int order = 0; int lastLineNumber = 0; - // Detect order lastType + // Detect order type for (ClassFileMemberDeclaration member : members) { int lineNumber = member.getFirstLineNumber(); diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index ddf4f803..74121967 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -35,7 +35,7 @@ public ClassFile loadClassFile(Loader loader, String internalTypeName) throws Ex } } - private ClassFile innerLoadClassFile(Loader loader, String internalTypeName) throws Exception { + protected ClassFile innerLoadClassFile(Loader loader, String internalTypeName) throws Exception { if (!loader.canLoad(internalTypeName)) { return null; } diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/DeserializeClassFileProcessor.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/DeserializeClassFileProcessor.java index cd81fdcd..3c608cb4 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/DeserializeClassFileProcessor.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/DeserializeClassFileProcessor.java @@ -13,7 +13,7 @@ import org.jd.core.v1.model.processor.Processor; /** - * Create a ClassFile model from a loader and a internal lastType name.

+ * Create a ClassFile model from a loader and a internal type name.

* * Input: -
* Output: {@link org.jd.core.v1.model.classfile.ClassFile}
diff --git a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java index c659a626..e0c943b4 100644 --- a/src/test/java/org/jd/core/v1/AnnotationConverterTest.java +++ b/src/test/java/org/jd/core/v1/AnnotationConverterTest.java @@ -62,7 +62,7 @@ public void test() throws Exception { assertEquals( "ExpressionElementValue{" + "FieldReferenceExpression{" + - "lastType=InnerObjectType{ObjectType{org/jd/core/test/annotation/Quality}.Lorg/jd/core/test/annotation/Quality$Level;}, " + + "type=InnerObjectType{ObjectType{org/jd/core/test/annotation/Quality}.Lorg/jd/core/test/annotation/Quality$Level;}, " + "expression=ObjectTypeReferenceExpression{InnerObjectType{ObjectType{org/jd/core/test/annotation/Quality}.Lorg/jd/core/test/annotation/Quality$Level;}}, " + "name=HIGH, " + "descriptor=Lorg/jd/core/test/annotation/Quality$Level;}" + diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index 35d3a422..f05d3a87 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -79,11 +79,11 @@ public void testJavaWriter() throws Exception { } // TODO In progress - @Test - public void testJodaTime() throws Exception { - // Decompile and recompile 'joda-time:joda-time:2.10.5' - test(org.joda.time.DateTime.class); - } +// @Test +// public void testJodaTime() throws Exception { +// // Decompile and recompile 'joda-time:joda-time:2.10.5' +// test(org.joda.time.DateTime.class); +// } @Test public void testJSoup() throws Exception { @@ -115,7 +115,6 @@ public void testSparkCore() throws Exception { test(spark.Spark.class); } - // TODO In progress @Test public void testLog4j() throws Exception { // Decompile and recompile 'log4j:log4j:1.2.17' @@ -123,11 +122,11 @@ public void testLog4j() throws Exception { } // TODO In progress - @Test - public void testGuava() throws Exception { - // Decompile and recompile 'com.google.guava:guava:12.0' - test(com.google.common.collect.Collections2.class); - } +// @Test +// public void testGuava() throws Exception { +// // Decompile and recompile 'com.google.guava:guava:12.0' +// test(com.google.common.collect.Collections2.class); +// } protected void test(Class clazz) throws Exception { test(new FileInputStream(Paths.get(clazz.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile())); @@ -150,7 +149,6 @@ protected void test(InputStream inputStream) throws Exception { Message message = new Message(); message.setHeader("loader", loader); message.setHeader("printer", printer); - // message.setHeader("configuration", Collections.singletonMap("realignLineNumbers", Boolean.TRUE)); message.setHeader("configuration", configuration); long time0 = System.currentTimeMillis(); From dfd7ecf0441d642fceed8f753ee4ca40bea56def Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 2 Feb 2020 17:55:59 +0100 Subject: [PATCH 160/211] Simplification of tests --- .../jd/core/v1/ClassFileToJavaSourceTest.java | 1198 ++--------------- 1 file changed, 86 insertions(+), 1112 deletions(-) diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index c1362fc6..558002af 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -9,6 +9,7 @@ import junit.framework.TestCase; import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; import org.jd.core.v1.compiler.CompilerUtil; import org.jd.core.v1.compiler.JavaSourceFileObject; import org.jd.core.v1.loader.ClassPathLoader; @@ -45,26 +46,8 @@ public void testJdk170Basic() throws Exception { String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("serialVersionUID = 9506606333927794L;") != -1); @@ -121,7 +104,6 @@ public void testJdk170Basic() throws Exception { assertTrue(source.indexOf("()") == -1); assertTrue(source.indexOf("NaND") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); @@ -132,24 +114,7 @@ public void testJdk170NoDebugInfoBasic() throws Exception { String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("System.out.println(\"hello\");"))); @@ -171,7 +136,6 @@ public void testJdk170NoDebugInfoBasic() throws Exception { assertTrue(source.indexOf("()") == -1); assertTrue(source.indexOf("NaND") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); @@ -182,24 +146,7 @@ public void testJdk170Constructors() throws Exception { String internalClassName = "org/jd/core/test/Constructors"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 28 */", "this.short123 = 1;"))); @@ -211,8 +158,6 @@ public void testJdk170Constructors() throws Exception { assertTrue(source.matches(PatternMaker.make(": 38 */", "this.int78 = int78;"))); assertTrue(source.matches(PatternMaker.make(": 39 */", "this.short123 = 3;"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -222,26 +167,8 @@ public void testJdk170IfElse() throws Exception { String internalClassName = "org/jd/core/test/IfElse"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 12: 12 */", "if (this == null)"))); @@ -273,8 +200,6 @@ public void testJdk170IfElse() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 172: 172 */", "if ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))"))); assertTrue(source.matches(PatternMaker.make("/* 184: 184 */", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -284,29 +209,11 @@ public void testJdk170Interface() throws Exception { String internalClassName = "org/jd/core/test/Interface"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("public interface Interface", "extends Serializable"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -316,26 +223,8 @@ public void testJdk170While() throws Exception { String internalClassName = "org/jd/core/test/While"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); @@ -353,8 +242,6 @@ public void testJdk170While() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -364,26 +251,8 @@ public void testJdk901While() throws Exception { String internalClassName = "org/jd/core/test/While"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); @@ -401,8 +270,6 @@ public void testJdk901While() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -412,26 +279,8 @@ public void testJdk1002While() throws Exception { String internalClassName = "org/jd/core/test/While"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); @@ -449,8 +298,6 @@ public void testJdk1002While() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -460,24 +307,7 @@ public void testJdk170DoWhile() throws Exception { String internalClassName = "org/jd/core/test/DoWhile"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); @@ -492,8 +322,6 @@ public void testJdk170DoWhile() throws Exception { assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -503,24 +331,7 @@ public void testJdk901DoWhile() throws Exception { String internalClassName = "org/jd/core/test/DoWhile"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); @@ -535,8 +346,6 @@ public void testJdk901DoWhile() throws Exception { assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -546,24 +355,7 @@ public void testJdk1002DoWhile() throws Exception { String internalClassName = "org/jd/core/test/DoWhile"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); @@ -578,8 +370,6 @@ public void testJdk1002DoWhile() throws Exception { assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -589,26 +379,8 @@ public void testJdk170BreakContinue() throws Exception { String internalClassName = "org/jd/core/test/BreakContinue"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "if (i == 1)"))); @@ -640,8 +412,6 @@ public void testJdk170BreakContinue() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 155: 0 */", "label16:", "do {"))); assertTrue(source.matches(PatternMaker.make("/* 162: 0 */", "break label16;"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -651,26 +421,8 @@ public void testJdk170For() throws Exception { String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); @@ -721,7 +473,6 @@ public void testJdk170For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.indexOf("/* 524: 524 */") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); @@ -732,24 +483,7 @@ public void testJdk170NoDebugInfoFor() throws Exception { String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); @@ -761,8 +495,6 @@ public void testJdk170NoDebugInfoFor() throws Exception { assertTrue(source.matches(PatternMaker.make("for (String str : paramArrayOfString)"))); assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors //assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -772,26 +504,8 @@ public void testJdk150For() throws Exception { String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 20 */", "for (byte b = 0; b < 10; b++)"))); @@ -805,8 +519,6 @@ public void testJdk150For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.matches(PatternMaker.make(": 427 */", "for (byte b = 0; b < 3; b++)"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @@ -816,26 +528,8 @@ public void testJdk160For() throws Exception { String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.6.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); @@ -849,8 +543,6 @@ public void testJdk160For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.6", new JavaSourceFileObject(internalClassName, source))); } @@ -860,26 +552,8 @@ public void testIbmJ9For() throws Exception { String internalClassName = "org/jd/core/test/For"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-ibm-j9_vm.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); @@ -892,8 +566,6 @@ public void testIbmJ9For() throws Exception { assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @@ -903,28 +575,8 @@ public void testJdk170Array() throws Exception { String internalClassName = "org/jd/core/test/Array"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - HashMap configuration = new HashMap<>(); - - configuration.put("realignLineNumbers", Boolean.FALSE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.FALSE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 12 */", "int[] i1 = new int[1];"))); @@ -941,8 +593,6 @@ public void testJdk170Array() throws Exception { assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][]", "{ { 1 } ,"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -952,28 +602,8 @@ public void testJdk150Array() throws Exception { String internalClassName = "org/jd/core/test/Array"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - HashMap configuration = new HashMap<>(); - - configuration.put("realignLineNumbers", Boolean.FALSE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.FALSE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 13 */", "int[][] arrayOfInt1 = new int[1][];"))); @@ -986,8 +616,6 @@ public void testJdk150Array() throws Exception { assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][] { { 1,"))); assertTrue(source.matches(PatternMaker.make(": 75 */", "testInt3(new int[][][] { { { 0, 1"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @@ -997,26 +625,8 @@ public void testJdk170Assert() throws Exception { String internalClassName = "org/jd/core/test/Assert"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); @@ -1027,8 +637,6 @@ public void testJdk170Assert() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -1038,26 +646,8 @@ public void testJdk150Assert() throws Exception { String internalClassName = "org/jd/core/test/Assert"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); @@ -1068,8 +658,6 @@ public void testJdk150Assert() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @@ -1079,26 +667,8 @@ public void testJdk150AnonymousClass() throws Exception { String internalClassName = "org/jd/core/test/AnonymousClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 21 */", "Object object = new Object()"))); @@ -1121,14 +691,13 @@ public void testJdk150AnonymousClass() throws Exception { assertTrue(source.indexOf("/* 111: 111 */") != -1); assertTrue(source.indexOf("{ ;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile( "1.5", new JavaSourceFileObject(internalClassName, source), new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") - )); + )); } @Test @@ -1136,26 +705,8 @@ public void testJdk170Switch() throws Exception { String internalClassName = "org/jd/core/test/Switch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "switch (i)"))); @@ -1191,8 +742,6 @@ public void testJdk170Switch() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 286: 0 */", "break;"))); assertTrue(source.matches(PatternMaker.make("/* 288: 0 */", "default:"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -1202,26 +751,8 @@ public void testJdk170AdvancedSwitch() throws Exception { String internalClassName = "org/jd/core/test/AdvancedSwitch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 13: 13 */", "A,", "B,", "C;"))); @@ -1243,8 +774,6 @@ public void testJdk170AdvancedSwitch() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 79: 0 */", "case \"POe\":"))); assertTrue(source.matches(PatternMaker.make("/* 80: 80 */", "System.out.println(\"'One' or 'POe'\");"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -1254,30 +783,11 @@ public void testEclipseJavaCompiler321Switch() throws Exception { String internalClassName = "org/jd/core/test/Switch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("/* 239: 239 */") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); @@ -1288,30 +798,11 @@ public void testEclipseJavaCompiler3130Switch() throws Exception { String internalClassName = "org/jd/core/test/Switch"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("/* 239: 239 */") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); @@ -1322,24 +813,7 @@ public void testJdk118TernaryOperator() throws Exception { String internalClassName = "org/jd/core/test/TernaryOperator"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str ="))); @@ -1357,8 +831,6 @@ public void testJdk118TernaryOperator() throws Exception { assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @@ -1368,24 +840,7 @@ public void testJdk170TernaryOperator() throws Exception { String internalClassName = "org/jd/core/test/TernaryOperator"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str = (s == null) ? \"1\" : \"2\";"))); @@ -1400,8 +855,6 @@ public void testJdk170TernaryOperator() throws Exception { assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -1411,26 +864,8 @@ public void testJdk170TryWithResources() throws Exception { String internalClassName = "org/jd/core/test/TryWithResources"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); @@ -1454,7 +889,6 @@ public void testJdk170TryWithResources() throws Exception { assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); assertTrue(source.indexOf("/* 162: 162 */") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); @@ -1465,26 +899,8 @@ public void testJdk180TryWithResources() throws Exception { String internalClassName = "org/jd/core/test/TryWithResources"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); @@ -1508,7 +924,6 @@ public void testJdk180TryWithResources() throws Exception { assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); assertTrue(source.indexOf("/* 162: 162 */") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); @@ -1519,24 +934,7 @@ public void testJdk170Synchronised() throws Exception { String internalClassName = "org/jd/core/test/Synchronized"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 11 */", "synchronized (paramStringBuilder)"))); @@ -1558,8 +956,6 @@ public void testJdk170Synchronised() throws Exception { assertTrue(source.matches(PatternMaker.make(": 95 */", "synchronized (s)"))); assertTrue(source.matches(PatternMaker.make(": 97 */", "return subContentEquals(s);"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -1569,26 +965,8 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); @@ -1607,8 +985,6 @@ public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); assertTrue(source.indexOf("Exception exception8;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); @@ -1621,26 +997,8 @@ public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); @@ -1671,8 +1029,6 @@ public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); assertTrue(source.indexOf("Exception exception8;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @@ -1682,26 +1038,8 @@ public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); @@ -1731,8 +1069,6 @@ public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); assertTrue(source.indexOf("Exception exception8;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); } @@ -1742,26 +1078,8 @@ public void testJdk118TryCatchFinally() throws Exception { String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); @@ -1791,8 +1109,6 @@ public void testJdk118TryCatchFinally() throws Exception { assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); assertTrue(source.indexOf("Exception exception8;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @@ -1802,26 +1118,8 @@ public void testJdk131TryCatchFinally() throws Exception { String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.3.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); @@ -1847,8 +1145,6 @@ public void testJdk131TryCatchFinally() throws Exception { assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); assertTrue(source.indexOf("Exception exception8;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @@ -1858,26 +1154,8 @@ public void testJdk170TryCatchFinally() throws Exception { String internalClassName = "org/jd/core/test/TryCatchFinally"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); @@ -1910,8 +1188,6 @@ public void testJdk170TryCatchFinally() throws Exception { assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); assertTrue(source.indexOf("Exception exception8;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -1921,24 +1197,7 @@ public void testJdk170AnnotatedClass() throws Exception { String internalClassName = "org/jd/core/test/AnnotatedClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - // PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.indexOf("@Quality(Quality.Level.HIGH)") != -1); @@ -1955,8 +1214,6 @@ public void testJdk170AnnotatedClass() throws Exception { assertTrue(source.indexOf("@Value(clazz = String.class)") != -1); assertTrue(source.indexOf("public void ping(@Deprecated Writer writer, @Deprecated @Value(str = \"localhost\") String host, long timeout)") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile( "1.7", @@ -1965,7 +1222,7 @@ public void testJdk170AnnotatedClass() throws Exception { new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String salutation() default \"\"; String value(); String last() default \"\";}"), new JavaSourceFileObject("org/jd/core/test/annotation/Quality", "package org.jd.core.test.annotation; public @interface Quality {enum Level {LOW,MIDDLE,HIGH}; Level value();}"), new JavaSourceFileObject("org/jd/core/test/annotation/Value", "package org.jd.core.test.annotation; public @interface Value {boolean z() default true; byte b() default 1; short s() default 1; int i() default 1; long l() default 1L; float f() default 1.0F; double d() default 1.0D; String str() default \"str\"; Class clazz() default Object.class;}") - )); + )); } @Test @@ -1973,26 +1230,8 @@ public void testJdk170AnonymousClass() throws Exception { String internalClassName = "org/jd/core/test/AnonymousClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - // PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 21 */", "Object obj = new Object()"))); @@ -2024,36 +1263,18 @@ public void testJdk170AnonymousClass() throws Exception { // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile( "1.7", - new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") - )); - } - - @Test - public void testJdk170GenericClass() throws Exception { - String internalClassName = "org/jd/core/test/GenericClass"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") + )); + } - printSource(source); + @Test + public void testJdk170GenericClass() throws Exception { + String internalClassName = "org/jd/core/test/GenericClass"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("public class GenericClass, T7 extends Map, T8 extends Map, T9 extends T8>") != -1); @@ -2073,7 +1294,6 @@ public void testJdk170GenericClass() throws Exception { assertTrue(source.matches(PatternMaker.make(": 104 */", "return (T1)this;"))); assertTrue(source.indexOf("/* 104: 104 */") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile( @@ -2088,38 +1308,19 @@ public void testJdk170AnnotationAuthor() throws Exception { String internalClassName = "org/jd/core/test/annotation/Author"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "public @interface Author"))); assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "Name value();"))); assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "Name[] contributors() default {};"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile( "1.7", new JavaSourceFileObject(internalClassName, source), new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") - )); + )); } @Test @@ -2127,24 +1328,7 @@ public void testJdk170AnnotationValue() throws Exception { String internalClassName = "org/jd/core/test/annotation/Value"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "@Retention(RetentionPolicy.RUNTIME)"))); @@ -2155,8 +1339,6 @@ public void testJdk170AnnotationValue() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "String str() default \"str\";"))); assertTrue(source.matches(PatternMaker.make("/* 27: 0 */", "Class clazz() default Object.class;"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -2166,27 +1348,8 @@ public void testJdk170OuterClass() throws Exception { String internalClassName = "org/jd/core/test/OuterClass"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //ClassPathLoader loader = new ClassPathLoader(); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 10 */", "protected int outerField1 = 0;"))); @@ -2241,8 +1404,6 @@ public void testJdk170OuterClass() throws Exception { assertTrue(source.matches(PatternMaker.make("public class InnerInnerClass", "{", "}"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); } @@ -2252,26 +1413,8 @@ public void testJdk170Enum() throws Exception { String internalClassName = "org/jd/core/test/Enum"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); @@ -2290,7 +1433,6 @@ public void testJdk170Enum() throws Exception { assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); assertTrue(source.indexOf("public static final enum") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); @@ -2301,26 +1443,8 @@ public void testJdk901Enum() throws Exception { String internalClassName = "org/jd/core/test/Enum"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); @@ -2339,7 +1463,6 @@ public void testJdk901Enum() throws Exception { assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); assertTrue(source.indexOf("public static final enum") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); @@ -2350,26 +1473,8 @@ public void testJdk1002Enum() throws Exception { String internalClassName = "org/jd/core/test/Enum"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); @@ -2388,7 +1493,6 @@ public void testJdk1002Enum() throws Exception { assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); assertTrue(source.indexOf("public static final enum") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); @@ -2399,26 +1503,8 @@ public void testJdk118Basic() throws Exception { String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); @@ -2428,8 +1514,6 @@ public void testJdk118Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return String.valueOf(str) + str;"))); assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); } @@ -2439,26 +1523,8 @@ public void testJdk142Basic() throws Exception { String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.4.2.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); @@ -2471,8 +1537,6 @@ public void testJdk142Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.4", new JavaSourceFileObject(internalClassName, source))); } @@ -2482,26 +1546,8 @@ public void testJdk901Basic() throws Exception { String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); @@ -2514,8 +1560,6 @@ public void testJdk901Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -2525,26 +1569,8 @@ public void testJdk1002Basic() throws Exception { String internalClassName = "org/jd/core/test/Basic"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); @@ -2557,8 +1583,6 @@ public void testJdk1002Basic() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -2568,24 +1592,7 @@ public void testJdk180Lambda() throws Exception { String internalClassName = "org/jd/core/test/Lambda"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make(": 16 */", "list.forEach(System.out::println);"))); @@ -2605,8 +1612,6 @@ public void testJdk180Lambda() throws Exception { assertTrue(source.matches(PatternMaker.make(": 66 */", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -2616,24 +1621,7 @@ public void testJdk901InterfaceWithDefaultMethods() throws Exception { String internalClassName = "org/jd/core/test/InterfaceWithDefaultMethods"; InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); // Check decompiled source code assertTrue(source.matches(PatternMaker.make("public interface InterfaceWithDefaultMethods"))); @@ -2650,8 +1638,6 @@ public void testJdk901InterfaceWithDefaultMethods() throws Exception { assertTrue(source.matches(PatternMaker.make("private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId)"))); assertTrue(source.matches(PatternMaker.make(": 40 */", "return ZonedDateTime.of(localDateTime, zoneId);"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors try { assertTrue(CompilerUtil.compile("1.9", new JavaSourceFileObject(internalClassName, source))); @@ -2670,26 +1656,8 @@ public void testBstMutationResult() throws Exception { Class mainClass = com.google.common.collect.Collections2.class; InputStream is = new FileInputStream(Paths.get(mainClass.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile()); Loader loader = new ZipLoader(is); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - - Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); // Check decompiled source code assertTrue(source.indexOf("N resultLeft, resultRight;") != -1); @@ -2697,8 +1665,6 @@ public void testBstMutationResult() throws Exception { assertTrue(source.matches(PatternMaker.make("/* 131:", "resultLeft = liftOriginalRoot.childOrNull(BstSide.LEFT);"))); assertTrue(source.matches(PatternMaker.make("/* 134:", "case LEFT:"))); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } @@ -2706,15 +1672,27 @@ public void testBstMutationResult() throws Exception { @Test public void testAnnotationUtils() throws Exception { String internalClassName = "org/apache/commons/lang3/AnnotationUtils"; - Loader loader = new ClassPathLoader(); - //PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); - PlainTextPrinter printer = new PlainTextPrinter(); Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName, configuration); + // Check decompiled source code + assertTrue(source.indexOf("setDefaultFullDetail(true);") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + @Test + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { Message message = new Message(); - message.setHeader("mainInternalTypeName", internalClassName); message.setHeader("loader", loader); message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); message.setHeader("configuration", configuration); deserializer.process(message); @@ -2728,13 +1706,9 @@ public void testAnnotationUtils() throws Exception { printSource(source); - // Check decompiled source code - assertTrue(source.indexOf("setDefaultFullDetail(true);") != -1); - assertTrue(source.indexOf("// Byte code:") == -1); - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + return source; } protected void printSource(String source) { From 1210d55a84d8c2fad14c743c8771cd495f109b54 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 2 Feb 2020 20:24:41 +0100 Subject: [PATCH 161/211] Code reformatting --- .../core/v1/JavaSyntaxToJavaSourceTest.java | 810 +++++++++--------- 1 file changed, 405 insertions(+), 405 deletions(-) diff --git a/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java index ca3b2aa9..0a2d9e1d 100644 --- a/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JavaSyntaxToJavaSourceTest.java @@ -45,97 +45,97 @@ public void testClassDeclaration() throws Exception { ObjectType printStreamType = new ObjectType("java/io/PrintStream", "java.io.PrintStream", "PrintStream"); CompilationUnit compilationUnit = new CompilationUnit( - new ClassDeclaration( - ClassDeclaration.FLAG_PUBLIC, - "org/jd/core/v1/service/test/TokenWriterTest", - "TokenWriterTest", - new BodyDeclaration( - "org/jd/core/v1/service/test/TokenWriterTest", - new MethodDeclaration( - MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, - "main", - PrimitiveType.TYPE_VOID, - new FormalParameter(ObjectType.TYPE_STRING.createType(1), "args"), - "([Ljava/lang/String;)V", - new Statements( - new IfStatement( - new BinaryOperatorExpression( - 8, + new ClassDeclaration( + ClassDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/TokenWriterTest", + "TokenWriterTest", + new BodyDeclaration( + "org/jd/core/v1/service/test/TokenWriterTest", + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, + "main", + PrimitiveType.TYPE_VOID, + new FormalParameter(ObjectType.TYPE_STRING.createType(1), "args"), + "([Ljava/lang/String;)V", + new Statements( + new IfStatement( + new BinaryOperatorExpression( + 8, + PrimitiveType.TYPE_BOOLEAN, + new LocalVariableReferenceExpression(8, stringArrayType, "args"), + "==", + new NullExpression(8, stringArrayType), + 9 + ), + ReturnStatement.RETURN + ), + new LocalVariableDeclarationStatement( + PrimitiveType.TYPE_INT, + new LocalVariableDeclarator( + "i", + new ExpressionVariableInitializer( + new MethodInvocationExpression( + 10, + PrimitiveType.TYPE_INT, + new ThisExpression(10, new ObjectType("org/jd/core/v1/service/test/TokenWriterTest", "org.jd.core.v1.service.writer.TokenWriterTest", "TokenWriterTest")), + "org/jd/core/v1/service/test/TokenWriterTest", + "call", + "(Ljava/lang/String;ILjava/util/Enumeration;C)I", + new Expressions( + new StringConstantExpression(11, "aaaa"), + new LocalVariableReferenceExpression(12, PrimitiveType.TYPE_INT, "b"), + new NewExpression( + 13, + new ObjectType("java/util/Enumeration", "java.util.Enumeration", "Enumeration"), + "()V", + new BodyDeclaration( + "java/util/Enumeration", + new MemberDeclarations( + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC, + "hasMoreElements", PrimitiveType.TYPE_BOOLEAN, - new LocalVariableReferenceExpression(8, stringArrayType, "args"), - "==", - new NullExpression(8, stringArrayType), - 9 - ), - ReturnStatement.RETURN - ), - new LocalVariableDeclarationStatement( - PrimitiveType.TYPE_INT, - new LocalVariableDeclarator( - "i", - new ExpressionVariableInitializer( - new MethodInvocationExpression( - 10, - PrimitiveType.TYPE_INT, - new ThisExpression(10, new ObjectType("org/jd/core/v1/service/test/TokenWriterTest", "org.jd.core.v1.service.writer.TokenWriterTest", "TokenWriterTest")), - "org/jd/core/v1/service/test/TokenWriterTest", - "call", - "(Ljava/lang/String;ILjava/util/Enumeration;C)I", - new Expressions( - new StringConstantExpression(11, "aaaa"), - new LocalVariableReferenceExpression(12, PrimitiveType.TYPE_INT, "b"), - new NewExpression( - 13, - new ObjectType("java/util/Enumeration", "java.util.Enumeration", "Enumeration"), - "()V", - new BodyDeclaration( - "java/util/Enumeration", - new MemberDeclarations( - new MethodDeclaration( - MethodDeclaration.FLAG_PUBLIC, - "hasMoreElements", - PrimitiveType.TYPE_BOOLEAN, - "()Z", - new ReturnExpressionStatement(new BooleanExpression(15, false)) - ), - new MethodDeclaration( - MethodDeclaration.FLAG_PUBLIC, - "nextElement", - ObjectType.TYPE_OBJECT, - "()Ljava/lang/Object;", - new ReturnExpressionStatement(new NullExpression(18, ObjectType.TYPE_OBJECT)) - ) - ) - ) - ), - new LocalVariableReferenceExpression(21, PrimitiveType.TYPE_CHAR, "c") - ) - ) - ) + "()Z", + new ReturnExpressionStatement(new BooleanExpression(15, false)) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC, + "nextElement", + ObjectType.TYPE_OBJECT, + "()Ljava/lang/Object;", + new ReturnExpressionStatement(new NullExpression(18, ObjectType.TYPE_OBJECT)) + ) ) + ) ), - new ExpressionStatement( - new MethodInvocationExpression( - 22, - PrimitiveType.TYPE_VOID, - new FieldReferenceExpression( - 22, - printStreamType, - new ObjectTypeReferenceExpression(22, new ObjectType("java/lang/System", "java.lang.System", "System")), - "java/lang/System", - "out", - "Ljava/io/PrintStream;" - ), - "java/io/PrintStream", - "println", - "(I)V", - new LocalVariableReferenceExpression(22, PrimitiveType.TYPE_INT, "i") - ) - ) + new LocalVariableReferenceExpression(21, PrimitiveType.TYPE_CHAR, "c") + ) ) + ) ) + ), + new ExpressionStatement( + new MethodInvocationExpression( + 22, + PrimitiveType.TYPE_VOID, + new FieldReferenceExpression( + 22, + printStreamType, + new ObjectTypeReferenceExpression(22, new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "out", + "Ljava/io/PrintStream;" + ), + "java/io/PrintStream", + "println", + "(I)V", + new LocalVariableReferenceExpression(22, PrimitiveType.TYPE_INT, "i") + ) + ) ) + ) ) + ) ); PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -172,12 +172,12 @@ public void testInterfaceDeclaration() throws Exception { ObjectType listType = new ObjectType("java/util/List", "java.util.List", "List", stringType); CompilationUnit compilationUnit = new CompilationUnit( - new InterfaceDeclaration( - InterfaceDeclaration.FLAG_PUBLIC, - "org/jd/core/v1/service/test/InterfaceTest", - "InterfaceTest", - new Types(listType, cloneableType) - ) + new InterfaceDeclaration( + InterfaceDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/InterfaceTest", + "InterfaceTest", + new Types(listType, cloneableType) + ) ); PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -211,23 +211,23 @@ public void testInterfaceDeclaration() throws Exception { @Test public void testEnumDayDeclaration() throws Exception { CompilationUnit compilationUnit = new CompilationUnit( - new EnumDeclaration( - null, - EnumDeclaration.FLAG_PUBLIC, - "org/jd/core/v1/service/test/Day", - "Day", - null, - Arrays.asList( - new EnumDeclaration.Constant("SUNDAY"), - new EnumDeclaration.Constant("MONDAY"), - new EnumDeclaration.Constant("TUESDAY"), - new EnumDeclaration.Constant("WEDNESDAY"), - new EnumDeclaration.Constant("THURSDAY"), - new EnumDeclaration.Constant("FRIDAY"), - new EnumDeclaration.Constant("SATURDAY") - ), - null - ) + new EnumDeclaration( + null, + EnumDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/Day", + "Day", + null, + Arrays.asList( + new EnumDeclaration.Constant("SUNDAY"), + new EnumDeclaration.Constant("MONDAY"), + new EnumDeclaration.Constant("TUESDAY"), + new EnumDeclaration.Constant("WEDNESDAY"), + new EnumDeclaration.Constant("THURSDAY"), + new EnumDeclaration.Constant("FRIDAY"), + new EnumDeclaration.Constant("SATURDAY") + ), + null + ) ); PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -265,253 +265,253 @@ public void testEnumPlanetDeclaration() throws Exception { ThisExpression thisExpression = new ThisExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")); CompilationUnit compilationUnit = new CompilationUnit( - new EnumDeclaration( - EnumDeclaration.FLAG_PUBLIC, - "org/jd/core/v1/service/test/Planet", - "Planet", - Arrays.asList( - new EnumDeclaration.Constant( - "MERCURY", - new Expressions( - new DoubleConstantExpression(3.303e+23), - new DoubleConstantExpression(2.4397e6) - ) + new EnumDeclaration( + EnumDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/Planet", + "Planet", + Arrays.asList( + new EnumDeclaration.Constant( + "MERCURY", + new Expressions( + new DoubleConstantExpression(3.303e+23), + new DoubleConstantExpression(2.4397e6) + ) + ), + new EnumDeclaration.Constant( + "VENUS", + new Expressions( + new DoubleConstantExpression(4.869e+24), + new DoubleConstantExpression(6.0518e6) + ) + ), + new EnumDeclaration.Constant( + "EARTH", + new Expressions( + new DoubleConstantExpression(5.976e+24), + new DoubleConstantExpression(6.37814e6) + ) + ) + ), + new BodyDeclaration( + "org/jd/core/v1/service/test/Planet", + new MemberDeclarations( + new FieldDeclaration(FieldDeclaration.FLAG_PRIVATE | FieldDeclaration.FLAG_FINAL, PrimitiveType.TYPE_DOUBLE, new FieldDeclarator("mass")), + new FieldDeclaration(FieldDeclaration.FLAG_PRIVATE | FieldDeclaration.FLAG_FINAL, PrimitiveType.TYPE_DOUBLE, new FieldDeclarator("radius")), + new ConstructorDeclaration( + 0, + new FormalParameters( + new FormalParameter(PrimitiveType.TYPE_DOUBLE, "mass"), + new FormalParameter(PrimitiveType.TYPE_DOUBLE, "radius") + ), + "(DD)V", + new Statements( + new ExpressionStatement(new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D"), + "=", + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "mass"), + 16 + )), + new ExpressionStatement(new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), + "=", + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "radius"), + 16 + )) + ) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PRIVATE, + "mass", + PrimitiveType.TYPE_DOUBLE, + "()D", + new ReturnExpressionStatement(new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D")) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PRIVATE, + "radius", + PrimitiveType.TYPE_DOUBLE, + "()D", + new ReturnExpressionStatement(new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D")) + ), + new FieldDeclaration( + FieldDeclaration.FLAG_PUBLIC | FieldDeclaration.FLAG_STATIC | FieldDeclaration.FLAG_FINAL, + PrimitiveType.TYPE_DOUBLE, + new FieldDeclarator("G", new ExpressionVariableInitializer(new DoubleConstantExpression(6.67300E-11))) + ), + new MethodDeclaration( + 0, + "surfaceGravity", + PrimitiveType.TYPE_DOUBLE, + "()D", + new ReturnExpressionStatement( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "G", "D"), + "*", + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D"), + "/", + new ParenthesesExpression(new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), + "*", + new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), + 4 + )), + 4 ), - new EnumDeclaration.Constant( - "VENUS", - new Expressions( - new DoubleConstantExpression(4.869e+24), - new DoubleConstantExpression(6.0518e6) - ) - ), - new EnumDeclaration.Constant( - "EARTH", - new Expressions( - new DoubleConstantExpression(5.976e+24), - new DoubleConstantExpression(6.37814e6) - ) + 4 ) + ) ), - new BodyDeclaration( - "org/jd/core/v1/service/test/Planet", - new MemberDeclarations( - new FieldDeclaration(FieldDeclaration.FLAG_PRIVATE | FieldDeclaration.FLAG_FINAL, PrimitiveType.TYPE_DOUBLE, new FieldDeclarator("mass")), - new FieldDeclaration(FieldDeclaration.FLAG_PRIVATE | FieldDeclaration.FLAG_FINAL, PrimitiveType.TYPE_DOUBLE, new FieldDeclarator("radius")), - new ConstructorDeclaration( - 0, - new FormalParameters( - new FormalParameter(PrimitiveType.TYPE_DOUBLE, "mass"), - new FormalParameter(PrimitiveType.TYPE_DOUBLE, "radius") - ), - "(DD)V", - new Statements( - new ExpressionStatement(new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_DOUBLE, - new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D"), - "=", - new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "mass"), - 16 - )), - new ExpressionStatement(new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_DOUBLE, - new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), - "=", - new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "radius"), - 16 - )) - ) - ), - new MethodDeclaration( - MethodDeclaration.FLAG_PRIVATE, - "mass", - PrimitiveType.TYPE_DOUBLE, - "()D", - new ReturnExpressionStatement(new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D")) - ), - new MethodDeclaration( - MethodDeclaration.FLAG_PRIVATE, - "radius", - PrimitiveType.TYPE_DOUBLE, - "()D", - new ReturnExpressionStatement(new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D")) - ), - new FieldDeclaration( - FieldDeclaration.FLAG_PUBLIC | FieldDeclaration.FLAG_STATIC | FieldDeclaration.FLAG_FINAL, + new MethodDeclaration( + 0, + "surfaceWeight", + PrimitiveType.TYPE_DOUBLE, + new FormalParameter(PrimitiveType.TYPE_DOUBLE, "otherMass"), + "(D)D", + new ReturnExpressionStatement( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "otherMass"), + "*", + new MethodInvocationExpression( + PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "surfaceGravity", "()D" + ), + 4 + ) + ) + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, + "surfaceWeight", + PrimitiveType.TYPE_VOID, + new FormalParameter(arrayOfStringType, "args"), + "([Ljava/lan/String;)V", + new Statements( + new IfStatement( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_BOOLEAN, + new LengthExpression(new LocalVariableReferenceExpression(arrayOfStringType, "args")), + "!=", + new IntegerConstantExpression(PrimitiveType.TYPE_INT, 1), + 9 + ), + new Statements( + new ExpressionStatement(new MethodInvocationExpression( + PrimitiveType.TYPE_VOID, + new FieldReferenceExpression( + printStreamType, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "out", + "Ljava/io/PrintStream;" + ), + "java/io/PrintStream", + "println", + "(Ljava/lang/String;)V", + new StringConstantExpression("Usage: java Planet ") + )), + new ExpressionStatement(new MethodInvocationExpression( + PrimitiveType.TYPE_VOID, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "exit", + "(I)V", + new IntegerConstantExpression(PrimitiveType.TYPE_INT, -1) + )) + ) + ), + new LocalVariableDeclarationStatement( + PrimitiveType.TYPE_DOUBLE, + new LocalVariableDeclarator("earthWeight", new ExpressionVariableInitializer( + new MethodInvocationExpression( + PrimitiveType.TYPE_DOUBLE, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/Double", "java.lang.Double", "Double")), + "java/lang/Double", + "parseDouble", + "(Ljava/lang/String;)D", + new ArrayExpression( + new LocalVariableReferenceExpression(arrayOfStringType, "args"), + new IntegerConstantExpression(PrimitiveType.TYPE_INT, 0) + ) + ) + )) + ), + new LocalVariableDeclarationStatement( + PrimitiveType.TYPE_DOUBLE, + new LocalVariableDeclarator("mass", new ExpressionVariableInitializer( + new BinaryOperatorExpression( + 0, + PrimitiveType.TYPE_DOUBLE, + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "earthWeight"), + "/", + new MethodInvocationExpression( PrimitiveType.TYPE_DOUBLE, - new FieldDeclarator("G", new ExpressionVariableInitializer(new DoubleConstantExpression(6.67300E-11))) - ), - new MethodDeclaration( - 0, + new FieldReferenceExpression( + planetType, + new ObjectTypeReferenceExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")), + "org/jd/core/v1/service/test/Planet", + "EARTH", + "org/jd/core/v1/service/test/Planet"), + "org/jd/core/v1/service/test/Planet", "surfaceGravity", - PrimitiveType.TYPE_DOUBLE, - "()D", - new ReturnExpressionStatement( - new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_DOUBLE, - new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "G", "D"), - "*", - new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_DOUBLE, - new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "mass", "D"), - "/", - new ParenthesesExpression(new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_DOUBLE, - new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), - "*", - new FieldReferenceExpression(PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "radius", "D"), - 4 - )), - 4 - ), - 4 - ) - ) + "()D" + ), + 4 + ) + )) + ), + new ForEachStatement( + planetType, + "p", + new MethodInvocationExpression( + planetType, + new ObjectTypeReferenceExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")), + "org/jd/core/v1/service/test/Planet", + "values", + "()[Lorg/jd/core/v1/service/test/Planet;"), + new ExpressionStatement(new MethodInvocationExpression( + PrimitiveType.TYPE_VOID, + new FieldReferenceExpression( + printStreamType, + new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), + "java/lang/System", + "out", + "Ljava/io/PrintStream;" ), - new MethodDeclaration( - 0, - "surfaceWeight", + "java/io/PrintStream", + "printf", + "(Ljava/lang/String;[Ljava/lang/Object;)V", + new Expressions( + new StringConstantExpression("Your weight on %s is %f%n"), + new LocalVariableReferenceExpression(planetType, "p"), + new MethodInvocationExpression( PrimitiveType.TYPE_DOUBLE, - new FormalParameter(PrimitiveType.TYPE_DOUBLE, "otherMass"), - "(D)D", - new ReturnExpressionStatement( - new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_DOUBLE, - new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "otherMass"), - "*", - new MethodInvocationExpression( - PrimitiveType.TYPE_DOUBLE, thisExpression, "org/jd/core/v1/service/test/Planet", "surfaceGravity", "()D" - ), - 4 - ) - ) - ), - new MethodDeclaration( - MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, + new LocalVariableReferenceExpression(planetType, "p"), + "org/jd/core/v1/service/test/Planet", "surfaceWeight", - PrimitiveType.TYPE_VOID, - new FormalParameter(arrayOfStringType, "args"), - "([Ljava/lan/String;)V", - new Statements( - new IfStatement( - new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_BOOLEAN, - new LengthExpression(new LocalVariableReferenceExpression(arrayOfStringType, "args")), - "!=", - new IntegerConstantExpression(PrimitiveType.TYPE_INT, 1), - 9 - ), - new Statements( - new ExpressionStatement(new MethodInvocationExpression( - PrimitiveType.TYPE_VOID, - new FieldReferenceExpression( - printStreamType, - new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), - "java/lang/System", - "out", - "Ljava/io/PrintStream;" - ), - "java/io/PrintStream", - "println", - "(Ljava/lang/String;)V", - new StringConstantExpression("Usage: java Planet ") - )), - new ExpressionStatement(new MethodInvocationExpression( - PrimitiveType.TYPE_VOID, - new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), - "java/lang/System", - "exit", - "(I)V", - new IntegerConstantExpression(PrimitiveType.TYPE_INT, -1) - )) - ) - ), - new LocalVariableDeclarationStatement( - PrimitiveType.TYPE_DOUBLE, - new LocalVariableDeclarator("earthWeight", new ExpressionVariableInitializer( - new MethodInvocationExpression( - PrimitiveType.TYPE_DOUBLE, - new ObjectTypeReferenceExpression(new ObjectType("java/lang/Double", "java.lang.Double", "Double")), - "java/lang/Double", - "parseDouble", - "(Ljava/lang/String;)D", - new ArrayExpression( - new LocalVariableReferenceExpression(arrayOfStringType, "args"), - new IntegerConstantExpression(PrimitiveType.TYPE_INT, 0) - ) - ) - )) - ), - new LocalVariableDeclarationStatement( - PrimitiveType.TYPE_DOUBLE, - new LocalVariableDeclarator("mass", new ExpressionVariableInitializer( - new BinaryOperatorExpression( - 0, - PrimitiveType.TYPE_DOUBLE, - new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "earthWeight"), - "/", - new MethodInvocationExpression( - PrimitiveType.TYPE_DOUBLE, - new FieldReferenceExpression( - planetType, - new ObjectTypeReferenceExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")), - "org/jd/core/v1/service/test/Planet", - "EARTH", - "org/jd/core/v1/service/test/Planet"), - "org/jd/core/v1/service/test/Planet", - "surfaceGravity", - "()D" - ), - 4 - ) - )) - ), - new ForEachStatement( - planetType, - "p", - new MethodInvocationExpression( - planetType, - new ObjectTypeReferenceExpression(new ObjectType("org/jd/core/v1/service/test/Planet", "org.jd.core.v1.service.test.Planet", "Planet")), - "org/jd/core/v1/service/test/Planet", - "values", - "()[Lorg/jd/core/v1/service/test/Planet;"), - new ExpressionStatement(new MethodInvocationExpression( - PrimitiveType.TYPE_VOID, - new FieldReferenceExpression( - printStreamType, - new ObjectTypeReferenceExpression(new ObjectType("java/lang/System", "java.lang.System", "System")), - "java/lang/System", - "out", - "Ljava/io/PrintStream;" - ), - "java/io/PrintStream", - "printf", - "(Ljava/lang/String;[Ljava/lang/Object;)V", - new Expressions( - new StringConstantExpression("Your weight on %s is %f%n"), - new LocalVariableReferenceExpression(planetType, "p"), - new MethodInvocationExpression( - PrimitiveType.TYPE_DOUBLE, - new LocalVariableReferenceExpression(planetType, "p"), - "org/jd/core/v1/service/test/Planet", - "surfaceWeight", - "(D)D", - new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "mass") - ) - ) - )) - ) - ) + "(D)D", + new LocalVariableReferenceExpression(PrimitiveType.TYPE_DOUBLE, "mass") + ) ) + )) ) + ) ) + ) ) + ) ); PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -540,47 +540,47 @@ public void testEnumPlanetDeclaration() throws Exception { @Test public void testSwitch() throws Exception { CompilationUnit compilationUnit = new CompilationUnit( - new ClassDeclaration( - ClassDeclaration.FLAG_PUBLIC, - "org/jd/core/v1/service/test/SwitchTest", - "SwitchTest", - new BodyDeclaration( - "org/jd/core/v1/service/test/SwitchTest", - new MethodDeclaration( - MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, - "translate", - PrimitiveType.TYPE_INT, - new FormalParameter(PrimitiveType.TYPE_INT, "i"), - "(I)Ljava/lang/String;", - new SwitchStatement( - new LocalVariableReferenceExpression(PrimitiveType.TYPE_INT, "i"), - Arrays.asList( - (SwitchStatement.Block)new SwitchStatement.LabelBlock( - new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 0)), - new Statements( - new LocalVariableDeclarationStatement( - ObjectType.TYPE_STRING, - new LocalVariableDeclarator("zero", new ExpressionVariableInitializer(new StringConstantExpression("zero"))) - ), - new ReturnExpressionStatement(new LocalVariableReferenceExpression(ObjectType.TYPE_STRING, "zero")) - ) - ), - new SwitchStatement.MultiLabelsBlock( - Arrays.asList( - (SwitchStatement.Label)new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 1)), - new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 2)) - ), - new ReturnExpressionStatement(new StringConstantExpression("one or two")) - ), - new SwitchStatement.LabelBlock( - SwitchStatement.DEFAULT_LABEL, - new ReturnExpressionStatement(new StringConstantExpression("other")) - ) - ) - ) + new ClassDeclaration( + ClassDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/SwitchTest", + "SwitchTest", + new BodyDeclaration( + "org/jd/core/v1/service/test/SwitchTest", + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC | MethodDeclaration.FLAG_STATIC, + "translate", + PrimitiveType.TYPE_INT, + new FormalParameter(PrimitiveType.TYPE_INT, "i"), + "(I)Ljava/lang/String;", + new SwitchStatement( + new LocalVariableReferenceExpression(PrimitiveType.TYPE_INT, "i"), + Arrays.asList( + (SwitchStatement.Block)new SwitchStatement.LabelBlock( + new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 0)), + new Statements( + new LocalVariableDeclarationStatement( + ObjectType.TYPE_STRING, + new LocalVariableDeclarator("zero", new ExpressionVariableInitializer(new StringConstantExpression("zero"))) + ), + new ReturnExpressionStatement(new LocalVariableReferenceExpression(ObjectType.TYPE_STRING, "zero")) + ) + ), + new SwitchStatement.MultiLabelsBlock( + Arrays.asList( + (SwitchStatement.Label)new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 1)), + new SwitchStatement.ExpressionLabel(new IntegerConstantExpression(PrimitiveType.TYPE_INT, 2)) + ), + new ReturnExpressionStatement(new StringConstantExpression("one or two")) + ), + new SwitchStatement.LabelBlock( + SwitchStatement.DEFAULT_LABEL, + new ReturnExpressionStatement(new StringConstantExpression("other")) ) + ) ) + ) ) + ) ); PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); @@ -610,33 +610,33 @@ public void testSwitch() throws Exception { @Test public void testBridgeAndSyntheticAttributes() throws Exception { CompilationUnit compilationUnit = new CompilationUnit( - new ClassDeclaration( - ClassDeclaration.FLAG_PUBLIC, - "org/jd/core/v1/service/test/SyntheticAttributeTest", - "SyntheticAttributeTest", - new BodyDeclaration( - "org/jd/core/v1/service/test/SyntheticAttributeTest", - new MemberDeclarations( - new FieldDeclaration( - FieldDeclaration.FLAG_PUBLIC|FieldDeclaration.FLAG_BRIDGE, - PrimitiveType.TYPE_INT, - new FieldDeclarator("i") - ), - new MethodDeclaration( - MethodDeclaration.FLAG_PUBLIC|MethodDeclaration.FLAG_BRIDGE, - "testBridgeAttribute", - PrimitiveType.TYPE_VOID, - "()V" - ), - new MethodDeclaration( - MethodDeclaration.FLAG_PUBLIC|MethodDeclaration.FLAG_SYNTHETIC, - "testSyntheticAttribute", - PrimitiveType.TYPE_VOID, - "()V" - ) - ) + new ClassDeclaration( + ClassDeclaration.FLAG_PUBLIC, + "org/jd/core/v1/service/test/SyntheticAttributeTest", + "SyntheticAttributeTest", + new BodyDeclaration( + "org/jd/core/v1/service/test/SyntheticAttributeTest", + new MemberDeclarations( + new FieldDeclaration( + FieldDeclaration.FLAG_PUBLIC|FieldDeclaration.FLAG_BRIDGE, + PrimitiveType.TYPE_INT, + new FieldDeclarator("i") + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC|MethodDeclaration.FLAG_BRIDGE, + "testBridgeAttribute", + PrimitiveType.TYPE_VOID, + "()V" + ), + new MethodDeclaration( + MethodDeclaration.FLAG_PUBLIC|MethodDeclaration.FLAG_SYNTHETIC, + "testSyntheticAttribute", + PrimitiveType.TYPE_VOID, + "()V" ) + ) ) + ) ); PlainTextMetaPrinter printer = new PlainTextMetaPrinter(); From 7fe6fc16ccca4e628a34d5e3ed8209e6cfe94522 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 2 Feb 2020 20:34:32 +0100 Subject: [PATCH 162/211] Improvement of readability of 'new' expressions --- .../javasyntax/expression/Expression.java | 2 +- .../model/javasyntax/expression/NewArray.java | 2 +- .../javasyntax/expression/NewExpression.java | 2 +- .../expression/NewInitializedArray.java | 2 +- .../core/v1/JavaOperatorPrecedenceTest.java | 90 +++++++++++++++++++ 5 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/test/java/org/jd/core/v1/JavaOperatorPrecedenceTest.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java index 0fe14207..74954837 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/Expression.java @@ -11,6 +11,7 @@ import org.jd.core.v1.model.javasyntax.type.Type; /* Priority Operator Operation Order of Evaluation + * 0 new Object creation * 1 [ ] Array index Left to Right * () Method call * . Member access @@ -22,7 +23,6 @@ * ~ Bitwise NOT * ! Boolean (logical) NOT * 3 (type) Type cast Right to Left - * new Object creation * 4 + String concatenation Left to Right * 5 * / % Multiplication, division, remainder Left to Right * 6 + - Addition, subtraction Left to Right diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java index 5dc77364..61be5dff 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java @@ -27,7 +27,7 @@ public void setDimensionExpressionList(BaseExpression dimensionExpressionList) { @Override public int getPriority() { - return 3; + return 0; } @Override diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java index fdb613ac..8f11341f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java @@ -49,7 +49,7 @@ public void setType(ObjectType type) { @Override public int getPriority() { - return 3; + return 0; } public String getDescriptor() { diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java index 570724ce..fdc695a9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java @@ -29,7 +29,7 @@ public ArrayVariableInitializer getArrayInitializer() { @Override public int getPriority() { - return 3; + return 0; } @Override diff --git a/src/test/java/org/jd/core/v1/JavaOperatorPrecedenceTest.java b/src/test/java/org/jd/core/v1/JavaOperatorPrecedenceTest.java new file mode 100644 index 00000000..e0f08ba3 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaOperatorPrecedenceTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.util.Collections; +import java.util.Map; + +public class JavaOperatorPrecedenceTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testNewOperatorPrecedence() throws Exception { + class NewOperatorPrecedence { + void test() {} + public /* static */ void main(String ... args) { + new NewOperatorPrecedence().test(); + } + } + + String internalClassName = NewOperatorPrecedence.class.getName().replace('.', '/'); + String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 44 */", "new NewOperatorPrecedence().test();"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} From a2517353adfb26964f9b2184065e27d720ed0a9d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 2 Feb 2020 20:35:06 +0100 Subject: [PATCH 163/211] Minimal code reformatting --- src/test/java/org/jd/core/v1/WriteTokenTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/jd/core/v1/WriteTokenTest.java b/src/test/java/org/jd/core/v1/WriteTokenTest.java index 4fd7f1dc..d098a158 100644 --- a/src/test/java/org/jd/core/v1/WriteTokenTest.java +++ b/src/test/java/org/jd/core/v1/WriteTokenTest.java @@ -16,7 +16,6 @@ import org.junit.Test; public class WriteTokenTest { - public static final KeywordToken PACKAGE = new KeywordToken("package"); public static final KeywordToken IF = new KeywordToken("if"); public static final KeywordToken IMPORT = new KeywordToken("import"); From ea7871b0254fd24e4173ad9f6d172a4573cbb845 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 2 Feb 2020 21:24:55 +0100 Subject: [PATCH 164/211] Minor updates --- src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java index 558002af..9e62f130 100644 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java @@ -29,7 +29,6 @@ import java.io.InputStream; import java.nio.file.Paths; import java.util.Collections; -import java.util.HashMap; import java.util.Map; public class ClassFileToJavaSourceTest extends TestCase { @@ -1682,12 +1681,10 @@ public void testAnnotationUtils() throws Exception { assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); } - @Test protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { return decompile(loader, printer, internalTypeName, Collections.emptyMap()); } - @Test protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { Message message = new Message(); message.setHeader("loader", loader); From dd618aef9c80a29a918a4c2c23d6d0add3548e05 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 2 Feb 2020 22:32:06 +0100 Subject: [PATCH 165/211] Fix #34: "Casts are omitted when casting floating point and integers" --- .../javasyntax/expression/CastExpression.java | 4 + .../util/ByteCodeParser.java | 35 ++++-- src/test/java/org/jd/core/v1/CfrTest.java | 108 ++++++++++++++++++ 3 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 src/test/java/org/jd/core/v1/CfrTest.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java index d00b6cc3..e450bec7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java @@ -43,6 +43,10 @@ public boolean isExplicit() { return explicit; } + public void setExplicit(boolean explicit) { + this.explicit = explicit; + } + @Override public int getPriority() { return 3; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 37167bd3..2e5dee5d 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -576,40 +576,40 @@ public void parse(BasicBlock basicBlock, Statements statements, DefaultStack configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} From 0c61c8a448b432002c00182510237a481f979b74 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 3 Feb 2020 20:57:39 +0100 Subject: [PATCH 166/211] Split tests --- .../jd/core/v1/ClassFileToJavaSourceTest.java | 1716 ----------------- .../jd/core/v1/JarFileToJavaSourceTest.java | 2 + .../org/jd/core/v1/Java9InterfaceTest.java | 107 + .../org/jd/core/v1/JavaAnnotationTest.java | 146 ++ .../jd/core/v1/JavaAnonymousClassTest.java | 154 ++ .../java/org/jd/core/v1/JavaArrayTest.java | 165 ++ .../java/org/jd/core/v1/JavaAssertTest.java | 115 ++ .../java/org/jd/core/v1/JavaBasicTest.java | 311 +++ .../java/org/jd/core/v1/JavaEnumTest.java | 165 ++ .../java/org/jd/core/v1/JavaGenericTest.java | 108 ++ .../java/org/jd/core/v1/JavaIfElseTest.java | 115 ++ .../jd/core/v1/JavaInnerOuterClassTest.java | 138 ++ .../java/org/jd/core/v1/JavaLambdaTest.java | 102 + .../java/org/jd/core/v1/JavaLoopTest.java | 427 ++++ .../java/org/jd/core/v1/JavaSwitchTest.java | 203 ++ .../jd/core/v1/JavaSynchronizedBlockTest.java | 104 + .../jd/core/v1/JavaTernaryOperatorTest.java | 124 ++ .../jd/core/v1/JavaTryCatchFinallyTest.java | 375 ++++ 18 files changed, 2861 insertions(+), 1716 deletions(-) delete mode 100644 src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java create mode 100644 src/test/java/org/jd/core/v1/Java9InterfaceTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaAnnotationTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaAnonymousClassTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaArrayTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaAssertTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaBasicTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaEnumTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaGenericTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaIfElseTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaInnerOuterClassTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaLambdaTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaLoopTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaSwitchTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaSynchronizedBlockTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaTernaryOperatorTest.java create mode 100644 src/test/java/org/jd/core/v1/JavaTryCatchFinallyTest.java diff --git a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java deleted file mode 100644 index 9e62f130..00000000 --- a/src/test/java/org/jd/core/v1/ClassFileToJavaSourceTest.java +++ /dev/null @@ -1,1716 +0,0 @@ -/* - * Copyright (c) 2008, 2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1; - -import junit.framework.TestCase; -import org.jd.core.v1.api.loader.Loader; -import org.jd.core.v1.api.printer.Printer; -import org.jd.core.v1.compiler.CompilerUtil; -import org.jd.core.v1.compiler.JavaSourceFileObject; -import org.jd.core.v1.loader.ClassPathLoader; -import org.jd.core.v1.loader.ZipLoader; -import org.jd.core.v1.model.message.Message; -import org.jd.core.v1.printer.PlainTextPrinter; -import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; -import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; -import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; -import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; -import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; -import org.jd.core.v1.service.writer.WriteTokenProcessor; -import org.jd.core.v1.regex.PatternMaker; -import org.junit.Test; - -import java.io.FileInputStream; -import java.io.InputStream; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.Map; - -public class ClassFileToJavaSourceTest extends TestCase { - protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); - protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); - protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); - protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); - //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); - protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); - protected WriteTokenProcessor writer = new WriteTokenProcessor(); - - @Test - public void testJdk170Basic() throws Exception { - String internalClassName = "org/jd/core/test/Basic"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("serialVersionUID = 9506606333927794L;") != -1); - assertTrue(source.indexOf(".indexOf('B');") != -1); - - assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "System.out.println(\"hello\");"))); - - assertTrue(source.indexOf("String str1 = \"3 == \" + (i + 1) + \" ?\";") != -1); - assertTrue(source.indexOf("String str2 = String.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); - assertTrue(source.indexOf("char c2 = '€';") != -1); - assertTrue(source.indexOf("char c3 = '\\'';") != -1); - assertTrue(source.indexOf("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');") != -1); - assertTrue(source.indexOf("Class class3 = String.class, class2 = class3, class1 = class2;") != -1); - assertTrue(source.matches(PatternMaker.make("Class class5 = doSomething(class6 = String.class, args1 = args2 = new String[], class4 = class5;"))); - assertTrue(source.matches(PatternMaker.make("int j = 1, k[] = {1, l[][] = {"))); - assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); - - assertTrue(source.matches(PatternMaker.make(": 60 */", "return new String[] {s, s + '?'};"))); - - assertTrue(source.indexOf("if (this instanceof Object)") != -1); - - assertTrue(source.indexOf("int k = 50 / (25 + (i = 789));") != -1); - assertTrue(source.matches(PatternMaker.make(": 82 */", "k = i += 100;"))); - assertTrue(source.matches(PatternMaker.make(": 87 */", "i = ++this.int78;"))); - assertTrue(source.matches(PatternMaker.make(": 88 */", "i = this.int78++;"))); - assertTrue(source.matches(PatternMaker.make(": 89 */", "i *= 10;"))); - assertTrue(source.matches(PatternMaker.make(": 91 */", "this.int78 = ++i;"))); - assertTrue(source.matches(PatternMaker.make(": 92 */", "this.int78 = i++;"))); - assertTrue(source.matches(PatternMaker.make(": 93 */", "this.int78 *= 10;"))); - assertTrue(source.matches(PatternMaker.make(": 95 */", "long34 = ++long12;"))); - assertTrue(source.matches(PatternMaker.make(": 96 */", "long34 = long12++;"))); - assertTrue(source.matches(PatternMaker.make(": 97 */", "long34 *= 10L;"))); - assertTrue(source.matches(PatternMaker.make(": 99 */", "i = (int)long12 + this.int78;"))); - assertTrue(source.matches(PatternMaker.make(": 101 */", "i = k ^ 0xFF;"))); - assertTrue(source.matches(PatternMaker.make(": 102 */", "i |= 0x7;"))); - - assertTrue(source.indexOf("int result;") != -1); - assertTrue(source.matches(PatternMaker.make(": 114 */", "result = 1;"))); - assertTrue(source.matches(PatternMaker.make(": 116 */", "int k = i;"))); - assertTrue(source.matches(PatternMaker.make(": 117 */", "result = k + 2;"))); - assertTrue(source.matches(PatternMaker.make(": 120 */", "result = this.short56;"))); - assertTrue(source.matches(PatternMaker.make(": 124 */", "return result;"))); - assertTrue(source.matches(PatternMaker.make(": 128 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); - assertTrue(source.matches(PatternMaker.make(": 130 */", "i = (int)(Basic.long12 + long12) + this.int78 + int78;"))); - - assertTrue(source.indexOf("public static native int read();") != -1); - - assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); - - assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); - - assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); - - assertTrue(source.indexOf("()") == -1); - assertTrue(source.indexOf("NaND") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170NoDebugInfoBasic() throws Exception { - String internalClassName = "org/jd/core/test/Basic"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("System.out.println(\"hello\");"))); - - assertTrue(source.matches(PatternMaker.make("String str1 = \"3 == \" + (paramInt + 1) + \" ?\";"))); - assertTrue(source.indexOf("String str2 = String.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); - assertTrue(source.matches(PatternMaker.make("char c2 = '€';"))); - assertTrue(source.matches(PatternMaker.make("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');"))); - assertTrue(source.matches(PatternMaker.make("Class clazz3 = String.class;"))); - assertTrue(source.matches(PatternMaker.make("Class clazz2 = clazz3;"))); - assertTrue(source.matches(PatternMaker.make("Class clazz1 = clazz2;"))); - assertTrue(source.indexOf("Class clazz5 = doSomething(clazz6 = String.class, arrayOfString1 = arrayOfString2 = new String[]") != -1); - - assertTrue(source.matches(PatternMaker.make("if (this instanceof Object)"))); - - assertTrue(source.matches(PatternMaker.make("this.int78 = 50 / (25 + (this.int78 = 789));"))); - - assertTrue(source.indexOf("protected static final Integer INTEGER_255 = new Integer(255);") != -1); - - assertTrue(source.indexOf("()") == -1); - assertTrue(source.indexOf("NaND") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170Constructors() throws Exception { - String internalClassName = "org/jd/core/test/Constructors"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 28 */", "this.short123 = 1;"))); - - assertTrue(source.matches(PatternMaker.make(": 32 */", "super(short56);"))); - assertTrue(source.matches(PatternMaker.make(": 33 */", "this.short123 = 2;"))); - - assertTrue(source.matches(PatternMaker.make(": 37 */", "this(short56);"))); - assertTrue(source.matches(PatternMaker.make(": 38 */", "this.int78 = int78;"))); - assertTrue(source.matches(PatternMaker.make(": 39 */", "this.short123 = 3;"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170IfElse() throws Exception { - String internalClassName = "org/jd/core/test/IfElse"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 12: 12 */", "if (this == null)"))); - assertTrue(source.matches(PatternMaker.make("/* 22: 22 */", "if (\"abc\".isEmpty() && \"abc\".isEmpty())"))); - - assertTrue(source.matches(PatternMaker.make("/* 32: 32 */", "if (this == null)"))); - assertTrue(source.matches(PatternMaker.make("/* 34: 0 */", "} else {"))); - - assertTrue(source.matches(PatternMaker.make("/* 44: 44 */", "if (this == null)"))); - assertTrue(source.matches(PatternMaker.make("/* 46: 46 */", "} else if (this == null) {"))); - assertTrue(source.matches(PatternMaker.make("/* 48: 0 */", "} else {"))); - - assertTrue(source.matches(PatternMaker.make("/* 58: 58 */", "if (i == 0)"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 60 */", "if (i == 1)"))); - - assertTrue(source.matches(PatternMaker.make("/* 71: 71 */", "if (i == System.currentTimeMillis())"))); - assertTrue(source.matches(PatternMaker.make("/* 73: 73 */", "} else if (i != System.currentTimeMillis()) {"))); - assertTrue(source.matches(PatternMaker.make("/* 75: 75 */", "} else if (i > System.currentTimeMillis()) {"))); - - assertTrue(source.matches(PatternMaker.make("/* 123: 123 */", "if (i == 4 && i == 5 && i == 6)"))); - - assertTrue(source.matches(PatternMaker.make("/* 135: 135 */", "if (i == 3 || i == 5 || i == 6)"))); - assertTrue(source.matches(PatternMaker.make("/* 137: 137 */", "} else if (i != 4 && i > 7 && i > 8) {"))); - assertTrue(source.matches(PatternMaker.make("/* 139: 0 */", "} else {"))); - - assertTrue(source.matches(PatternMaker.make("/* 148: 148 */", "if ((i == 1 && i == 2 && i == 3) || (i == 4 && i == 5 && i == 6) || (i == 7 && i == 8 && i == 9))"))); - assertTrue(source.matches(PatternMaker.make("/* 160: 160 */", "if ((i == 1 || i == 2 || i == 3) && (i == 4 || i == 5 || i == 6) && (i == 7 || i == 8 || i == 9))"))); - - assertTrue(source.matches(PatternMaker.make("/* 172: 172 */", "if ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))"))); - assertTrue(source.matches(PatternMaker.make("/* 184: 184 */", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170Interface() throws Exception { - String internalClassName = "org/jd/core/test/Interface"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("public interface Interface", "extends Serializable"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170While() throws Exception { - String internalClassName = "org/jd/core/test/While"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); - assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); - assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); - assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); - assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); - assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); - assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); - assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk901While() throws Exception { - String internalClassName = "org/jd/core/test/While"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); - assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); - assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); - assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); - assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); - assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); - assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); - assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk1002While() throws Exception { - String internalClassName = "org/jd/core/test/While"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); - assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); - assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); - assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); - assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); - assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); - assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); - assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170DoWhile() throws Exception { - String internalClassName = "org/jd/core/test/DoWhile"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); - assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); - assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); - assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); - assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); - assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); - assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); - assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk901DoWhile() throws Exception { - String internalClassName = "org/jd/core/test/DoWhile"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); - assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); - assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); - assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); - assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); - assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); - assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); - assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk1002DoWhile() throws Exception { - String internalClassName = "org/jd/core/test/DoWhile"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); - assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); - assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); - assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); - assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); - assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); - assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); - assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170BreakContinue() throws Exception { - String internalClassName = "org/jd/core/test/BreakContinue"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "if (i == 1)"))); - assertTrue(source.matches(PatternMaker.make("/* 16: 0 */", "continue;"))); - assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "if (i == 2)"))); - assertTrue(source.matches(PatternMaker.make("/* 19: 0 */", "continue;"))); - - assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "label18: while (i > 1)"))); - assertTrue(source.matches(PatternMaker.make("/* 37: 0 */", "continue label18;"))); - assertTrue(source.matches(PatternMaker.make("/* 40: 0 */", "break label18;"))); - - assertTrue(source.matches(PatternMaker.make("/* 54: 54 */", "label17: while (i > 1)"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 63: 0 */", "continue label17;"))); - - assertTrue(source.matches(PatternMaker.make("/* 78: 0 */", "label13:"))); - assertTrue(source.matches(PatternMaker.make("/* 83: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 86: 0 */", "break label13;"))); - - assertTrue(source.matches(PatternMaker.make("/* 101: 0 */", "label15:", "do {"))); - assertTrue(source.matches(PatternMaker.make("/* 106: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 109: 0 */", "break label15;"))); - - assertTrue(source.matches(PatternMaker.make("/* 123: 0 */", "label24:", "do {"))); - assertTrue(source.matches(PatternMaker.make("/* 133: 0 */", "continue label24;"))); - assertTrue(source.matches(PatternMaker.make("/* 135: 0 */", "break label24;"))); - assertTrue(source.matches(PatternMaker.make("/* 138: 0 */", "break label23;"))); - - assertTrue(source.matches(PatternMaker.make("/* 155: 0 */", "label16:", "do {"))); - assertTrue(source.matches(PatternMaker.make("/* 162: 0 */", "break label16;"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170For() throws Exception { - String internalClassName = "org/jd/core/test/For"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 42 */", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 44 */", "for (; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 54 */", "for (; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 64 */", "for (int i = 0;; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 72 */", "for (;; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 80 */", "for (int i = 0; i < 10;)"))); - assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 96 */", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make("/* 104: 0 */", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 112 */", "for (int i = 0, j = i, size = 10; i < size; j += ++i)"))); - assertTrue(source.matches(PatternMaker.make(": 122 */", "int i = 0, j = i, size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 123 */", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 124 */", "j += ++i)"))); - assertTrue(source.matches(PatternMaker.make(": 134 */", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 135 */", "int j = i;"))); - assertTrue(source.matches(PatternMaker.make(": 136 */", "int size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 137 */", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 138 */", "i++,"))); - assertTrue(source.matches(PatternMaker.make(": 139 */", "j += i)"))); - assertTrue(source.matches(PatternMaker.make(": 149 */", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 151 */", "int j = i;"))); - assertTrue(source.matches(PatternMaker.make(": 153 */", "int size = 10;"))); - assertTrue(source.matches(PatternMaker.make(": 155 */", "for (; i < size;"))); - assertTrue(source.matches(PatternMaker.make(": 157 */", "i++,"))); - assertTrue(source.matches(PatternMaker.make(": 159 */", "j += i)"))); - assertTrue(source.matches(PatternMaker.make(": 169 */", "for (int i = 0; i < 10; i++);"))); - assertTrue(source.matches(PatternMaker.make(": 177 */", "for (; i < 10; i++);"))); - assertTrue(source.matches(PatternMaker.make(": 185 */", "for (int i = 0;; i++);"))); - assertTrue(source.matches(PatternMaker.make("/* 190: 0 */", "while (true)"))); - assertTrue(source.matches(PatternMaker.make(": 191 */", "i++;"))); - assertTrue(source.matches(PatternMaker.make(": 197 */", "for (int i = 0; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 203 */", "for (int[] i = { 0 }; i.length < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 209 */", "for (int i = 0, j = i, k = i; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 215 */", "for (int[] i = { 0 }, j = i, k = j; i.length < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 221 */", "for (int i = 0, j[] = { 1 }; i < 10;);"))); - assertTrue(source.matches(PatternMaker.make(": 227 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 233 */", "int i = 0;"))); - assertTrue(source.matches(PatternMaker.make("/* 234: 0 */", "while (true);"))); - assertTrue(source.matches(PatternMaker.make(": 245 */", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); - assertTrue(source.matches(PatternMaker.make("/* 253: 0 */", "while (true) {"))); - assertTrue(source.matches(PatternMaker.make(": 264 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make(": 389 */", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 403 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - - assertTrue(source.indexOf("/* 524: 524 */") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170NoDebugInfoFor() throws Exception { - String internalClassName = "org/jd/core/test/For"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); - assertTrue(source.matches(PatternMaker.make("for (byte b = 0;; b++)"))); - assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); - assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); - assertTrue(source.matches(PatternMaker.make("for (paramInt = 0; paramInt < 10; paramInt++)"))); - assertTrue(source.matches(PatternMaker.make("for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("for (String str : paramArrayOfString)"))); - assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); - - // Recompile decompiled source code and check errors - //assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk150For() throws Exception { - String internalClassName = "org/jd/core/test/For"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 20 */", "for (byte b = 0; b < 10; b++)"))); - assertTrue(source.matches(PatternMaker.make(": 88 */", "while (paramInt < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 273 */", "for (paramInt = 0; paramInt < 10; paramInt++)"))); - assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int i : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do {"))); - assertTrue(source.matches(PatternMaker.make(": 349 */", "while (b < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String str : paramArrayOfString)"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String str : paramList)"))); - assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "for (byte b = 0; b < 3; b++)"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk160For() throws Exception { - String internalClassName = "org/jd/core/test/For"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.6.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 273 */", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do {"))); - assertTrue(source.matches(PatternMaker.make(": 349 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.6", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testIbmJ9For() throws Exception { - String internalClassName = "org/jd/core/test/For"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-ibm-j9_vm.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); - assertTrue(source.matches(PatternMaker.make(": 273 */", "for (i = 0; i < 10; i++)"))); - assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); - assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do"))); - assertTrue(source.matches(PatternMaker.make(": 349 */", "while (i < 10);"))); - assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String s : array)"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String s : list)"))); - assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170Array() throws Exception { - String internalClassName = "org/jd/core/test/Array"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.FALSE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 12 */", "int[] i1 = new int[1];"))); - assertTrue(source.matches(PatternMaker.make(": 13 */", "int[][] i2 = new int[1][];"))); - assertTrue(source.matches(PatternMaker.make(": 14 */", "int[][][] i3 = new int[1][][];"))); - assertTrue(source.matches(PatternMaker.make(": 15 */", "int[][][] i4 = new int[1][2][];"))); - assertTrue(source.matches(PatternMaker.make(": 22 */", "String[][][][] s5 = new String[1][2][][];"))); - - assertTrue(source.matches(PatternMaker.make(": 26 */", "byte[] b1 = { 1, 2 } ;"))); - assertTrue(source.matches(PatternMaker.make(": 27 */", "byte[][] b2 = { { 1, 2 } } ;"))); - assertTrue(source.matches(PatternMaker.make(": 28 */", "byte[][][][] b3 = { { { 3, 4 } } } ;"))); - - assertTrue(source.matches(PatternMaker.make(": 48 */", "testException1(new Exception[]", "{ new Exception(\"1\") } );"))); - - assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][]", "{ { 1 } ,"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk150Array() throws Exception { - String internalClassName = "org/jd/core/test/Array"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.FALSE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 13 */", "int[][] arrayOfInt1 = new int[1][];"))); - assertTrue(source.matches(PatternMaker.make(": 30 */", "int[][] arrayOfInt1 = { { 0, 1, 2"))); - - assertTrue(source.matches(PatternMaker.make(": 52 */", "testException2(new Exception[][]", "{ { new Exception(\"1\")"))); - - assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][] { { 1,"))); - - assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][] { { 1,"))); - assertTrue(source.matches(PatternMaker.make(": 75 */", "testInt3(new int[][][] { { { 0, 1"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170Assert() throws Exception { - String internalClassName = "org/jd/core/test/Assert"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); - assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "assert i == 0 || i == 1;"))); - assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "assert i == 2 && i < 3;"))); - - assertTrue(source.matches(PatternMaker.make("/* 34: 34 */", "assert new BigDecimal(i) == BigDecimal.ONE;"))); - - assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk150Assert() throws Exception { - String internalClassName = "org/jd/core/test/Assert"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); - assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "assert paramInt == 0 || paramInt == 1;"))); - assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "assert paramInt == 2 && paramInt < 3;"))); - - assertTrue(source.matches(PatternMaker.make("/* 34: 34 */", "assert new BigDecimal(paramInt) == BigDecimal.ONE;"))); - - assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk150AnonymousClass() throws Exception { - String internalClassName = "org/jd/core/test/AnonymousClass"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 21 */", "Object object = new Object()"))); - assertTrue(source.matches(PatternMaker.make(": 23 */", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); - - assertTrue(source.matches(PatternMaker.make(": 37 */", "final long l1 = System.currentTimeMillis();"))); - assertTrue(source.matches(PatternMaker.make(": 39 */", "Enumeration enumeration = new Enumeration()"))); - assertTrue(source.matches(PatternMaker.make(": 40 */", "Iterator i = AnonymousClass.this.list.iterator();"))); - assertTrue(source.matches(PatternMaker.make(": 44 */", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); - assertTrue(source.indexOf("return this.i.next();") != -1); - assertTrue(source.matches(PatternMaker.make(": 52 */", "test(enumeration, \"test\");"))); - assertTrue(source.matches(PatternMaker.make(": 55 */", "System.out.println(\"end\");"))); - - assertTrue(source.matches(PatternMaker.make(": 67 */", "if (s1 == s2 && i == 5)"))); - - assertTrue(source.matches(PatternMaker.make(": 90 */", "Serializable serializable = new Serializable()"))); - assertTrue(source.matches(PatternMaker.make(": 96 */", "return (abc.equals(param2Object) || def.equals(param2Object) || str1.equals(param2Object) || str2.equals(param2Object));"))); - assertTrue(source.matches(PatternMaker.make(": 104 */", "System.out.println(\"end\");"))); - - assertTrue(source.indexOf("/* 111: 111 */") != -1); - - assertTrue(source.indexOf("{ ;") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile( - "1.5", - new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") - )); - } - - @Test - public void testJdk170Switch() throws Exception { - String internalClassName = "org/jd/core/test/Switch"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "switch (i)"))); - assertTrue(source.matches(PatternMaker.make("/* 16: 0 */", "case 0:"))); - assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "System.out.println(\"0\");"))); - assertTrue(source.matches(PatternMaker.make("/* 18: 0 */", "break;"))); - - assertTrue(source.matches(PatternMaker.make("/* 34: 0 */", "case 0:"))); - assertTrue(source.matches(PatternMaker.make("/* 35: 35 */", "System.out.println(\"0\");"))); - assertTrue(source.matches(PatternMaker.make("/* 36: 0 */", "case 1:"))); - - assertTrue(source.matches(PatternMaker.make("/* 56: 0 */", "default:"))); - - assertTrue(source.matches(PatternMaker.make("/* 110: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 111: 0 */", "case 1:"))); - assertTrue(source.matches(PatternMaker.make("/* 112: 112 */", "System.out.println(\"1\");"))); - assertTrue(source.matches(PatternMaker.make("/* 113: 113 */", "throw new RuntimeException(\"boom\");"))); - - assertTrue(source.matches(PatternMaker.make("/* 134: 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make("/* 171: 0 */", "case 3:"))); - assertTrue(source.matches(PatternMaker.make("/* 172: 0 */", "case 4:"))); - assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "System.out.println(\"3 or 4\");"))); - assertTrue(source.matches(PatternMaker.make("/* 174: 0 */", "break;"))); - - assertTrue(source.matches(PatternMaker.make("/* 265: 0 */", "case 1:"))); - assertTrue(source.matches(PatternMaker.make("/* 266: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 267: 0 */", "default:"))); - - assertTrue(source.matches(PatternMaker.make("/* 283: 0 */", "case 1:"))); - assertTrue(source.matches(PatternMaker.make("/* 284: 0 */", "case 2:"))); - assertTrue(source.matches(PatternMaker.make("/* 285: 0 */", "case 3:"))); - assertTrue(source.matches(PatternMaker.make("/* 286: 0 */", "break;"))); - assertTrue(source.matches(PatternMaker.make("/* 288: 0 */", "default:"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170AdvancedSwitch() throws Exception { - String internalClassName = "org/jd/core/test/AdvancedSwitch"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 13: 13 */", "A,", "B,", "C;"))); - - assertTrue(source.matches(PatternMaker.make("/* 19: 19 */", "switch (te)"))); - assertTrue(source.matches(PatternMaker.make("/* 20: 0 */", "case A:"))); - assertTrue(source.matches(PatternMaker.make("/* 22: 0 */", "case B:"))); - assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "case C:"))); - - assertTrue(source.matches(PatternMaker.make("/* 39: 0 */", "case A:"))); - assertTrue(source.matches(PatternMaker.make("/* 40: 0 */", "case B:"))); - assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "System.out.println(\"A or B\");"))); - - assertTrue(source.matches(PatternMaker.make("/* 56: 56 */", "switch (str)"))); - assertTrue(source.matches(PatternMaker.make("/* 57: 0 */", "case \"One\":"))); - assertTrue(source.matches(PatternMaker.make("/* 58: 58 */", "System.out.println(1);"))); - - assertTrue(source.matches(PatternMaker.make("/* 78: 0 */", "case \"One\":"))); - assertTrue(source.matches(PatternMaker.make("/* 79: 0 */", "case \"POe\":"))); - assertTrue(source.matches(PatternMaker.make("/* 80: 80 */", "System.out.println(\"'One' or 'POe'\");"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testEclipseJavaCompiler321Switch() throws Exception { - String internalClassName = "org/jd/core/test/Switch"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("/* 239: 239 */") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testEclipseJavaCompiler3130Switch() throws Exception { - String internalClassName = "org/jd/core/test/Switch"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("/* 239: 239 */") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk118TernaryOperator() throws Exception { - String internalClassName = "org/jd/core/test/TernaryOperator"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str ="))); - assertTrue(source.matches(PatternMaker.make(": 14 */", "(s == null) ?"))); - assertTrue(source.matches(PatternMaker.make(": 15 */", "\"1\""))); - assertTrue(source.matches(PatternMaker.make(": 16 */", "\"2\";"))); - assertTrue(source.matches(PatternMaker.make(": 24 */", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); - assertTrue(source.matches(PatternMaker.make(": 34 */", "return !(s != s || time < time);"))); - assertTrue(source.matches(PatternMaker.make(": 40 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 60 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 71 */", "if ((s1 == null) ? false : (s1.length() > 0))"))); - assertTrue(source.matches(PatternMaker.make(": 82 */", "if (s1 != null && s1.length() > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 126 */", "if (s1 == null && false)"))); - assertTrue(source.matches(PatternMaker.make(": 137 */", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170TernaryOperator() throws Exception { - String internalClassName = "org/jd/core/test/TernaryOperator"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str = (s == null) ? \"1\" : \"2\";"))); - assertTrue(source.matches(PatternMaker.make(": 24 */", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); - assertTrue(source.matches(PatternMaker.make(": 34 */", "return (s == s && time >= time);"))); - assertTrue(source.matches(PatternMaker.make(": 40 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 60 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); - assertTrue(source.matches(PatternMaker.make(": 71 */", "if (s1 != null && s1.length() > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 82 */", "if (s1 != null && s1.length() > 0)"))); - assertTrue(source.matches(PatternMaker.make(": 126 */", "if (s1 == null);"))); - assertTrue(source.matches(PatternMaker.make(": 137 */", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); - assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170TryWithResources() throws Exception { - String internalClassName = "org/jd/core/test/TryWithResources"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); - - assertTrue(source.matches(PatternMaker.make(": 49 */", "try (FileInputStream input = new FileInputStream(path))"))); - assertTrue(source.matches(PatternMaker.make(": 57 */", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 59 */", "System.out.println(\"finally\");"))); - - assertTrue(source.matches(PatternMaker.make(": 121 */", "try(FileInputStream input = new FileInputStream(pathIn);"))); - assertTrue(source.matches(PatternMaker.make(": 122 */", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); - assertTrue(source.matches(PatternMaker.make(": 123 */", "FileOutputStream output = new FileOutputStream(pathOut);"))); - assertTrue(source.matches(PatternMaker.make(": 124 */", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); - assertTrue(source.matches(PatternMaker.make(": 132 */", "if (data == -7)"))); - assertTrue(source.matches(PatternMaker.make(": 133 */", "return 1;"))); - assertTrue(source.matches(PatternMaker.make(": 142 */", "return 2;"))); - assertTrue(source.matches(PatternMaker.make(": 144 */", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 150 */", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 152 */", "System.out.println(\"finally, before loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 156 */", "System.out.println(\"finally, after loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 159 */", "System.out.println(\"finally\");"))); - assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); - - assertTrue(source.indexOf("/* 162: 162 */") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk180TryWithResources() throws Exception { - String internalClassName = "org/jd/core/test/TryWithResources"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); - - assertTrue(source.matches(PatternMaker.make(": 49 */", "try (FileInputStream input = new FileInputStream(path))"))); - assertTrue(source.matches(PatternMaker.make(": 57 */", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 59 */", "System.out.println(\"finally\");"))); - - assertTrue(source.matches(PatternMaker.make(": 121 */", "try(FileInputStream input = new FileInputStream(pathIn);"))); - assertTrue(source.matches(PatternMaker.make(": 122 */", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); - assertTrue(source.matches(PatternMaker.make(": 123 */", "FileOutputStream output = new FileOutputStream(pathOut);"))); - assertTrue(source.matches(PatternMaker.make(": 124 */", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); - assertTrue(source.matches(PatternMaker.make(": 132 */", "if (data == -7)"))); - assertTrue(source.matches(PatternMaker.make(": 133 */", "return 1;"))); - assertTrue(source.matches(PatternMaker.make(": 142 */", "return 2;"))); - assertTrue(source.matches(PatternMaker.make(": 144 */", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 150 */", "e.printStackTrace();"))); - assertTrue(source.matches(PatternMaker.make(": 152 */", "System.out.println(\"finally, before loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 156 */", "System.out.println(\"finally, after loop\");"))); - assertTrue(source.matches(PatternMaker.make(": 159 */", "System.out.println(\"finally\");"))); - assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); - - assertTrue(source.indexOf("/* 162: 162 */") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170Synchronised() throws Exception { - String internalClassName = "org/jd/core/test/Synchronized"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 11 */", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 13 */", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 15 */", "return 2;"))); - - assertTrue(source.matches(PatternMaker.make(": 20 */", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 22 */", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 23 */", "return 2;"))); - - assertTrue(source.matches(PatternMaker.make(": 29 */", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 31 */", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make(": 73 */", "synchronized (paramStringBuilder)"))); - assertTrue(source.matches(PatternMaker.make(": 75 */", "inSynchronized();"))); - assertTrue(source.matches(PatternMaker.make(": 76 */", "throw new RuntimeException();"))); - - assertTrue(source.matches(PatternMaker.make(": 95 */", "synchronized (s)"))); - assertTrue(source.matches(PatternMaker.make(": 97 */", "return subContentEquals(s);"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { - String internalClassName = "org/jd/core/test/TryCatchFinally"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("/* 45: 45 */", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - - // TODO assertTrue(source.matches(PatternMaker.make("/* 217:", "inCatch1();"))); - - assertTrue(source.indexOf("/* 888: 888 */") != -1); - - assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); - assertTrue(source.indexOf("catch (RuntimeException null)") == -1); - assertTrue(source.indexOf("Object object;") == -1); - assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); - assertTrue(source.indexOf("Exception exception8;") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - - System.out.println(ClassFileToJavaSourceTest.class.getProtectionDomain().getCodeSource().getLocation().getPath()); - System.out.println(System.getProperty("java.class.path")); - } - - @Test - public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { - String internalClassName = "org/jd/core/test/TryCatchFinally"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); - assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - - assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - assertTrue(source.indexOf("/* 400: 0] inFinally();") == -1); - - assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - - assertTrue(source.indexOf("/* 888: 888 */") != -1); - - assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); - assertTrue(source.indexOf("catch (RuntimeException null)") == -1); - assertTrue(source.indexOf("Object object;") == -1); - assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); - assertTrue(source.indexOf("Exception exception8;") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { - String internalClassName = "org/jd/core/test/TryCatchFinally"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); - assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - - assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - - assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - - assertTrue(source.indexOf("/* 888: 888 */") != -1); - - assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); - assertTrue(source.indexOf("catch (RuntimeException null)") == -1); - assertTrue(source.indexOf("Object object;") == -1); - assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); - assertTrue(source.indexOf("Exception exception8;") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk118TryCatchFinally() throws Exception { - String internalClassName = "org/jd/core/test/TryCatchFinally"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - - assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - - assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - - assertTrue(source.indexOf("/* 902: 902 */") != -1); - - assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); - assertTrue(source.indexOf("catch (RuntimeException null)") == -1); - assertTrue(source.indexOf("Object object;") == -1); - assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); - assertTrue(source.indexOf("Exception exception8;") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk131TryCatchFinally() throws Exception { - String internalClassName = "org/jd/core/test/TryCatchFinally"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.3.1.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - - assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - - assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - - assertTrue(source.indexOf("/* 902: 902 */") != -1); - - assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); - assertTrue(source.indexOf("catch (RuntimeException null)") == -1); - assertTrue(source.indexOf("Object object;") == -1); - assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); - assertTrue(source.indexOf("Exception exception8;") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170TryCatchFinally() throws Exception { - String internalClassName = "org/jd/core/test/TryCatchFinally"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); - assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); - - assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); - - assertTrue(source.matches(PatternMaker.make(": 192 */", "catch (RuntimeException e) {}"))); - assertTrue(source.matches(PatternMaker.make("/* 204: 0 */", "finally {}"))); - - assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); - assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); - assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); - assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); - - assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); - assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); - assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); - assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); - assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); - assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); - assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); - - assertTrue(source.indexOf("/* 902: 902 */") != -1); - - assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); - assertTrue(source.indexOf("catch (RuntimeException null)") == -1); - assertTrue(source.indexOf("Object object;") == -1); - assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); - assertTrue(source.indexOf("Exception exception8;") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170AnnotatedClass() throws Exception { - String internalClassName = "org/jd/core/test/AnnotatedClass"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.indexOf("@Quality(Quality.Level.HIGH)") != -1); - assertTrue(source.indexOf("@Author(value = @Name(salutation = \"Mr\", value = \"Donald\", last = \"Duck\"), contributors = {@Name(\"Huey\"), @Name(\"Dewey\"), @Name(\"Louie\")})") != -1); - assertTrue(source.indexOf("@Value(z = true)") != -1); - assertTrue(source.indexOf("@Value(b = -15)") != -1); - assertTrue(source.indexOf("@Value(s = -15)") != -1); - assertTrue(source.indexOf("@Value(i = 1)") != -1); - assertTrue(source.indexOf("@Value(l = 1234567890123456789L)") != -1); - assertTrue(source.indexOf("@Value(f = 123.456F)") != -1); - assertTrue(source.indexOf("@Value(d = 789.101112D)") != -1); - assertTrue(source.indexOf("@Value(str = \"str\")") != -1); - assertTrue(source.indexOf("@Value(str = \"str \u0083 उ ᄉ\")") != -1); - assertTrue(source.indexOf("@Value(clazz = String.class)") != -1); - assertTrue(source.indexOf("public void ping(@Deprecated Writer writer, @Deprecated @Value(str = \"localhost\") String host, long timeout)") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile( - "1.7", - new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Author", "package org.jd.core.test.annotation; public @interface Author {Name value(); Name[] contributors() default {};}"), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String salutation() default \"\"; String value(); String last() default \"\";}"), - new JavaSourceFileObject("org/jd/core/test/annotation/Quality", "package org.jd.core.test.annotation; public @interface Quality {enum Level {LOW,MIDDLE,HIGH}; Level value();}"), - new JavaSourceFileObject("org/jd/core/test/annotation/Value", "package org.jd.core.test.annotation; public @interface Value {boolean z() default true; byte b() default 1; short s() default 1; int i() default 1; long l() default 1L; float f() default 1.0F; double d() default 1.0D; String str() default \"str\"; Class clazz() default Object.class;}") - )); - } - - @Test - public void testJdk170AnonymousClass() throws Exception { - String internalClassName = "org/jd/core/test/AnonymousClass"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 21 */", "Object obj = new Object()"))); - assertTrue(source.matches(PatternMaker.make(": 23 */", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); - - assertTrue(source.matches(PatternMaker.make(": 39 */", "Enumeration e = new Enumeration()"))); - assertTrue(source.matches(PatternMaker.make(": 40 */", "Iterator i = AnonymousClass.this.list.iterator();"))); - assertTrue(source.matches(PatternMaker.make(": 44 */", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); - - assertTrue(source.matches(PatternMaker.make(": 61 */", "final int i = s1.length();"))); - assertTrue(source.matches(PatternMaker.make(": 63 */", "System.out.println(\"2\" + new StringWrapper(123456L)"))); - assertTrue(source.matches(PatternMaker.make(": 67 */", "if (s1 == s2 && i == 5)"))); - assertTrue(source.matches(PatternMaker.make("/* 72: 0 */", "} + \"3\");"))); - - assertTrue(source.matches(PatternMaker.make(": 81 */", "final Object abc = \"abc\";"))); - assertTrue(source.matches(PatternMaker.make(": 82 */", "final Object def = \"def\";"))); - assertTrue(source.matches(PatternMaker.make(": 84 */", "Serializable serializable = new Serializable()"))); - assertTrue(source.matches(PatternMaker.make(": 90 */", "Serializable serializable = new Serializable()"))); - assertTrue(source.matches(PatternMaker.make(": 96 */", "return (abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj));"))); - assertTrue(source.matches(PatternMaker.make(": 100 */", "return (abc.equals(obj) || def.equals(obj));"))); - assertTrue(source.matches(PatternMaker.make("/* 102: 0 */", "};"))); - - assertTrue(source.matches(PatternMaker.make(": 111 */", "this.l = l & 0x80L;"))); - - assertTrue(source.indexOf("{ ;") == -1); - assertTrue(source.indexOf("} ;") == -1); - assertTrue(source.indexOf("// Byte code:") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile( - "1.7", - new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") - )); - } - - @Test - public void testJdk170GenericClass() throws Exception { - String internalClassName = "org/jd/core/test/GenericClass"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("public class GenericClass, T7 extends Map, T8 extends Map, T9 extends T8>") != -1); - assertTrue(source.indexOf("extends ArrayList") != -1); - assertTrue(source.indexOf("implements Serializable, Comparable") != -1); - - assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "public List> list1 = new ArrayList<>();"))); - assertTrue(source.indexOf("public List> list2;") != -1); - assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "list2 = new ArrayList<>();"))); - - assertTrue(source.indexOf("public void fromArrayToCollection(T[] a, Collection c)") != -1); - assertTrue(source.indexOf("public void copy(List dest, List src)") != -1); - assertTrue(source.indexOf("public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException") != -1); - assertTrue(source.indexOf("public List print(List list) throws T2, InvalidParameterException") != -1); - - assertTrue(source.matches(PatternMaker.make(": 100 */", "return call(0);"))); - assertTrue(source.matches(PatternMaker.make(": 104 */", "return (T1)this;"))); - - assertTrue(source.indexOf("/* 104: 104 */") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile( - "1.7", - new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/AnnotatedClass", "package org.jd.core.test; public class AnnotatedClass {}") - )); - } - - @Test - public void testJdk170AnnotationAuthor() throws Exception { - String internalClassName = "org/jd/core/test/annotation/Author"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "public @interface Author"))); - assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "Name value();"))); - assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "Name[] contributors() default {};"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile( - "1.7", - new JavaSourceFileObject(internalClassName, source), - new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") - )); - } - - @Test - public void testJdk170AnnotationValue() throws Exception { - String internalClassName = "org/jd/core/test/annotation/Value"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "@Retention(RetentionPolicy.RUNTIME)"))); - assertTrue(source.matches(PatternMaker.make("/* 9: 0 */", "@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})"))); - assertTrue(source.matches(PatternMaker.make("/* 10: 0 */", "public @interface Value {"))); - assertTrue(source.matches(PatternMaker.make("/* 11: 0 */", "boolean z() default true;"))); - assertTrue(source.matches(PatternMaker.make("/* 13: 0 */", "byte b() default 1;"))); - assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "String str() default \"str\";"))); - assertTrue(source.matches(PatternMaker.make("/* 27: 0 */", "Class clazz() default Object.class;"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170OuterClass() throws Exception { - String internalClassName = "org/jd/core/test/OuterClass"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 10 */", "protected int outerField1 = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 11 */", "protected String[] outerField2 = { \"0\" };"))); - - assertTrue(source.indexOf("final int localVariable1 = param1;") != -1); - assertTrue(source.indexOf("final String[] localVariable2 = param2;") != -1); - - assertTrue(source.matches(PatternMaker.make(": 21 */", "InnerClass innerClass = new InnerClass(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 22 */", "innerClass.innerMethod(localVariable1, localVariable2);"))); - assertTrue(source.matches(PatternMaker.make(": 24 */", "StaticInnerClass staticInnerClass = new StaticInnerClass(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 25 */", "staticInnerClass.innerMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make(": 27 */", "InnerClass anonymousClass = new InnerClass(param1, param2)"))); - assertTrue(source.indexOf("public void innerMethod(int param1, String... param2)") != -1); - assertTrue(source.matches(PatternMaker.make(": 30 */", "this.innerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 32 */", "OuterClass.this.outerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 33 */", "OuterClass.this.outerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 35 */", "this.innerField1 = localVariable1;"))); - assertTrue(source.matches(PatternMaker.make(": 36 */", "this.innerField2 = localVariable2;"))); - - assertTrue(source.matches(PatternMaker.make(": 39 */", "anonymousClass.innerMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make(": 41 */", "StaticInnerClass staticAnonymousClass = new StaticInnerClass(param1, param2)"))); - assertTrue(source.matches(PatternMaker.make(": 44 */", "this.innerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 46 */", "OuterClass.this.outerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 47 */", "OuterClass.this.outerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 49 */", "this.innerField1 = localVariable1;"))); - assertTrue(source.matches(PatternMaker.make(": 50 */", "this.innerField2 = localVariable2;"))); - - assertTrue(source.matches(PatternMaker.make(": 53 */", "staticAnonymousClass.innerMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make(": 55 */", "InnerEnum.A.innerMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make("/* 56: 0 */", "class LocalClass"))); - assertTrue(source.matches(PatternMaker.make(": 58 */", "protected int innerField1 = 0;"))); - assertTrue(source.matches(PatternMaker.make(": 59 */", "protected String[] innerField2 = { \"0\" } ;"))); - assertTrue(source.matches(PatternMaker.make(": 69 */", "this.innerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 70 */", "this.innerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 72 */", "OuterClass.this.outerField1 = param1;"))); - assertTrue(source.matches(PatternMaker.make(": 73 */", "OuterClass.this.outerField2 = param2;"))); - assertTrue(source.matches(PatternMaker.make(": 75 */", "this.innerField1 = localVariable1;"))); - assertTrue(source.matches(PatternMaker.make(": 76 */", "this.innerField2 = localVariable2;"))); - assertTrue(source.matches(PatternMaker.make(": 94 */", "LocalClass localClass = new LocalClass(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 95 */", "localClass.localMethod(localVariable1, localVariable2);"))); - - assertTrue(source.matches(PatternMaker.make(": 114 */", "this(param1, param2);"))); - assertTrue(source.matches(PatternMaker.make(": 144 */", "this(param1, param2);"))); - - assertTrue(source.matches(PatternMaker.make(": 158 */", "A,", "B,", "C;"))); - assertTrue(source.indexOf("/* 182: 182 */") != -1); - - assertTrue(source.matches(PatternMaker.make("public class InnerInnerClass", "{", "}"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk170Enum() throws Exception { - String internalClassName = "org/jd/core/test/Enum"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); - - assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); - assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); - assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); - assertTrue(source.indexOf("this.mass = mass;") != -1); - assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); - assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); - assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); - assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); - assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); - assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); - - assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); - - assertTrue(source.indexOf("public static final enum") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk901Enum() throws Exception { - String internalClassName = "org/jd/core/test/Enum"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); - - assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); - assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); - assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); - assertTrue(source.indexOf("this.mass = mass;") != -1); - assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); - assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); - assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); - assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); - assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); - assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); - - assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); - - assertTrue(source.indexOf("public static final enum") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk1002Enum() throws Exception { - String internalClassName = "org/jd/core/test/Enum"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); - - assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); - assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); - assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); - assertTrue(source.indexOf("this.mass = mass;") != -1); - assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); - assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); - assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); - assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); - assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); - assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); - - assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); - - assertTrue(source.indexOf("public static final enum") == -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk118Basic() throws Exception { - String internalClassName = "org/jd/core/test/Basic"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); - assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); - assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make(": 128 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); - assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return String.valueOf(str) + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk142Basic() throws Exception { - String internalClassName = "org/jd/core/test/Basic"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.4.2.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); - assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); - assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); - assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); - assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.4", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk901Basic() throws Exception { - String internalClassName = "org/jd/core/test/Basic"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); - assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); - assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); - assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); - assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk1002Basic() throws Exception { - String internalClassName = "org/jd/core/test/Basic"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); - assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); - assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); - assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); - assertTrue(source.indexOf("public static native int read();") != -1); - assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); - assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); - assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); - assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk180Lambda() throws Exception { - String internalClassName = "org/jd/core/test/Lambda"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 16 */", "list.forEach(System.out::println);"))); - assertTrue(source.matches(PatternMaker.make(": 20 */", "list.stream().filter(s -> (s != null)).forEach(s -> System.out.println(s));"))); - assertTrue(source.indexOf("Predicate filter = s -> (s.length() == length);") != -1); - assertTrue(source.indexOf("Consumer println = s -> System.out.println(s);") != -1); - assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter(filter).forEach(println);"))); - assertTrue(source.matches(PatternMaker.make(": 31 */", "((Map)list.stream()"))); - assertTrue(source.matches(PatternMaker.make(": 32 */", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))"))); - assertTrue(source.matches(PatternMaker.make(": 33 */", ".forEach((key, value) ->"))); - assertTrue(source.matches(PatternMaker.make(": 48 */", "Thread thread = new Thread(() -> {"))); - assertTrue(source.matches(PatternMaker.make(": 58 */", "Consumer staticMethodReference = String::valueOf;"))); - assertTrue(source.matches(PatternMaker.make(": 59 */", "BiFunction methodReference = String::compareTo;"))); - assertTrue(source.matches(PatternMaker.make(": 60 */", "Supplier instanceMethodReference = s::toString;"))); - assertTrue(source.matches(PatternMaker.make(": 61 */", "Supplier constructorReference = String::new;"))); - assertTrue(source.matches(PatternMaker.make(": 65 */", "MethodType mtToString = MethodType.methodType(String.class);"))); - assertTrue(source.matches(PatternMaker.make(": 66 */", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); - assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testJdk901InterfaceWithDefaultMethods() throws Exception { - String internalClassName = "org/jd/core/test/InterfaceWithDefaultMethods"; - InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); - Loader loader = new ZipLoader(is); - String source = decompile(loader, new PlainTextPrinter(), internalClassName); - - // Check decompiled source code - assertTrue(source.matches(PatternMaker.make("public interface InterfaceWithDefaultMethods"))); - assertTrue(source.matches(PatternMaker.make("void setTime(int paramInt1, int paramInt2, int paramInt3);"))); - assertTrue(source.matches(PatternMaker.make("LocalDateTime getLocalDateTime();"))); - assertTrue(source.matches(PatternMaker.make("static ZoneId getZoneId(String zoneString)"))); - assertTrue(source.matches(PatternMaker.make(": 24 */", "return unsafeGetZoneId(zoneString);"))); - assertTrue(source.matches(PatternMaker.make(": 26 */", "System.err.println(\"Invalid time zone: \" + zoneString + \"; using default time zone instead.\");"))); - assertTrue(source.matches(PatternMaker.make(": 27 */", "return ZoneId.systemDefault();"))); - assertTrue(source.matches(PatternMaker.make("default ZonedDateTime getZonedDateTime(String zoneString)"))); - assertTrue(source.matches(PatternMaker.make(": 32 */", "return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString));"))); - assertTrue(source.matches(PatternMaker.make("private static ZoneId unsafeGetZoneId(String zoneString)"))); - assertTrue(source.matches(PatternMaker.make(": 36 */", "return ZoneId.of(zoneString);"))); - assertTrue(source.matches(PatternMaker.make("private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId)"))); - assertTrue(source.matches(PatternMaker.make(": 40 */", "return ZonedDateTime.of(localDateTime, zoneId);"))); - - // Recompile decompiled source code and check errors - try { - assertTrue(CompilerUtil.compile("1.9", new JavaSourceFileObject(internalClassName, source))); - } catch (IllegalArgumentException e) { - if (e.getMessage().contains("invalid source release: 1.9")) { - System.err.println("testJdk901InterfaceWithDefaultMethods() need a Java SDK 9+"); - } else { - assertTrue("Compilation failed: " + e.getMessage(), false); - } - } - } - - @Test - public void testBstMutationResult() throws Exception { - String internalClassName = "com/google/common/collect/BstMutationResult"; - Class mainClass = com.google.common.collect.Collections2.class; - InputStream is = new FileInputStream(Paths.get(mainClass.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile()); - Loader loader = new ZipLoader(is); - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("N resultLeft, resultRight;") != -1); - assertTrue(source.indexOf("assert false;") == -1); - assertTrue(source.matches(PatternMaker.make("/* 131:", "resultLeft = liftOriginalRoot.childOrNull(BstSide.LEFT);"))); - assertTrue(source.matches(PatternMaker.make("/* 134:", "case LEFT:"))); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - @Test - public void testAnnotationUtils() throws Exception { - String internalClassName = "org/apache/commons/lang3/AnnotationUtils"; - Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); - String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName, configuration); - - // Check decompiled source code - assertTrue(source.indexOf("setDefaultFullDetail(true);") != -1); - - // Recompile decompiled source code and check errors - assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); - } - - protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { - return decompile(loader, printer, internalTypeName, Collections.emptyMap()); - } - - protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { - Message message = new Message(); - message.setHeader("loader", loader); - message.setHeader("printer", printer); - message.setHeader("mainInternalTypeName", internalTypeName); - message.setHeader("configuration", configuration); - - deserializer.process(message); - converter.process(message); - fragmenter.process(message); - layouter.process(message); - tokenizer.process(message); - writer.process(message); - - String source = printer.toString(); - - printSource(source); - - assertTrue(source.indexOf("// Byte code:") == -1); - - return source; - } - - protected void printSource(String source) { - System.out.println("- - - - - - - - "); - System.out.println(source); - System.out.println("- - - - - - - - "); - } -} diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index f05d3a87..c129e3ee 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -158,6 +158,8 @@ protected void test(InputStream inputStream) throws Exception { String internalTypeName = path.substring(0, path.length() - 6); // 6 = ".class".length() // TODO DEBUG if (!internalTypeName.endsWith("/Rule")) continue; + //if (!internalTypeName.endsWith("/TypeUtils")) continue; + if (!internalTypeName.endsWith("/Parameterized")) continue; message.setHeader("mainInternalTypeName", internalTypeName); printer.init(); diff --git a/src/test/java/org/jd/core/v1/Java9InterfaceTest.java b/src/test/java/org/jd/core/v1/Java9InterfaceTest.java new file mode 100644 index 00000000..bbfd1766 --- /dev/null +++ b/src/test/java/org/jd/core/v1/Java9InterfaceTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class Java9InterfaceTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk901InterfaceWithDefaultMethods() throws Exception { + String internalClassName = "org/jd/core/test/InterfaceWithDefaultMethods"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("public interface InterfaceWithDefaultMethods"))); + assertTrue(source.matches(PatternMaker.make("void setTime(int paramInt1, int paramInt2, int paramInt3);"))); + assertTrue(source.matches(PatternMaker.make("LocalDateTime getLocalDateTime();"))); + assertTrue(source.matches(PatternMaker.make("static ZoneId getZoneId(String zoneString)"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "return unsafeGetZoneId(zoneString);"))); + assertTrue(source.matches(PatternMaker.make(": 26 */", "System.err.println(\"Invalid time zone: \" + zoneString + \"; using default time zone instead.\");"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "return ZoneId.systemDefault();"))); + assertTrue(source.matches(PatternMaker.make("default ZonedDateTime getZonedDateTime(String zoneString)"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "return getZonedDateTime(getLocalDateTime(), getZoneId(zoneString));"))); + assertTrue(source.matches(PatternMaker.make("private static ZoneId unsafeGetZoneId(String zoneString)"))); + assertTrue(source.matches(PatternMaker.make(": 36 */", "return ZoneId.of(zoneString);"))); + assertTrue(source.matches(PatternMaker.make("private ZonedDateTime getZonedDateTime(LocalDateTime localDateTime, ZoneId zoneId)"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "return ZonedDateTime.of(localDateTime, zoneId);"))); + + // Recompile decompiled source code and check errors + try { + assertTrue(CompilerUtil.compile("1.9", new JavaSourceFileObject(internalClassName, source))); + } catch (IllegalArgumentException e) { + if (e.getMessage().contains("invalid source release: 1.9")) { + System.err.println("testJdk901InterfaceWithDefaultMethods() need a Java SDK 9+"); + } else { + assertTrue("Compilation failed: " + e.getMessage(), false); + } + } + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaAnnotationTest.java b/src/test/java/org/jd/core/v1/JavaAnnotationTest.java new file mode 100644 index 00000000..d2b76ed1 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaAnnotationTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaAnnotationTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170AnnotatedClass() throws Exception { + String internalClassName = "org/jd/core/test/AnnotatedClass"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.indexOf("@Quality(Quality.Level.HIGH)") != -1); + assertTrue(source.indexOf("@Author(value = @Name(salutation = \"Mr\", value = \"Donald\", last = \"Duck\"), contributors = {@Name(\"Huey\"), @Name(\"Dewey\"), @Name(\"Louie\")})") != -1); + assertTrue(source.indexOf("@Value(z = true)") != -1); + assertTrue(source.indexOf("@Value(b = -15)") != -1); + assertTrue(source.indexOf("@Value(s = -15)") != -1); + assertTrue(source.indexOf("@Value(i = 1)") != -1); + assertTrue(source.indexOf("@Value(l = 1234567890123456789L)") != -1); + assertTrue(source.indexOf("@Value(f = 123.456F)") != -1); + assertTrue(source.indexOf("@Value(d = 789.101112D)") != -1); + assertTrue(source.indexOf("@Value(str = \"str\")") != -1); + assertTrue(source.indexOf("@Value(str = \"str \u0083 उ ᄉ\")") != -1); + assertTrue(source.indexOf("@Value(clazz = String.class)") != -1); + assertTrue(source.indexOf("public void ping(@Deprecated Writer writer, @Deprecated @Value(str = \"localhost\") String host, long timeout)") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Author", "package org.jd.core.test.annotation; public @interface Author {Name value(); Name[] contributors() default {};}"), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String salutation() default \"\"; String value(); String last() default \"\";}"), + new JavaSourceFileObject("org/jd/core/test/annotation/Quality", "package org.jd.core.test.annotation; public @interface Quality {enum Level {LOW,MIDDLE,HIGH}; Level value();}"), + new JavaSourceFileObject("org/jd/core/test/annotation/Value", "package org.jd.core.test.annotation; public @interface Value {boolean z() default true; byte b() default 1; short s() default 1; int i() default 1; long l() default 1L; float f() default 1.0F; double d() default 1.0D; String str() default \"str\"; Class clazz() default Object.class;}") + )); + } + + @Test + public void testJdk170AnnotationAuthor() throws Exception { + String internalClassName = "org/jd/core/test/annotation/Author"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 3: 0 */", "public @interface Author"))); + assertTrue(source.matches(PatternMaker.make("/* 4: 0 */", "Name value();"))); + assertTrue(source.matches(PatternMaker.make("/* 6: 0 */", "Name[] contributors() default {};"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") + )); + } + + @Test + public void testJdk170AnnotationValue() throws Exception { + String internalClassName = "org/jd/core/test/annotation/Value"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 8: 0 */", "@Retention(RetentionPolicy.RUNTIME)"))); + assertTrue(source.matches(PatternMaker.make("/* 9: 0 */", "@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})"))); + assertTrue(source.matches(PatternMaker.make("/* 10: 0 */", "public @interface Value {"))); + assertTrue(source.matches(PatternMaker.make("/* 11: 0 */", "boolean z() default true;"))); + assertTrue(source.matches(PatternMaker.make("/* 13: 0 */", "byte b() default 1;"))); + assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "String str() default \"str\";"))); + assertTrue(source.matches(PatternMaker.make("/* 27: 0 */", "Class clazz() default Object.class;"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaAnonymousClassTest.java b/src/test/java/org/jd/core/v1/JavaAnonymousClassTest.java new file mode 100644 index 00000000..c6d2a2fa --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaAnonymousClassTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaAnonymousClassTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk150AnonymousClass() throws Exception { + String internalClassName = "org/jd/core/test/AnonymousClass"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 21 */", "Object object = new Object()"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); + + assertTrue(source.matches(PatternMaker.make(": 37 */", "final long l1 = System.currentTimeMillis();"))); + assertTrue(source.matches(PatternMaker.make(": 39 */", "Enumeration enumeration = new Enumeration()"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "Iterator i = AnonymousClass.this.list.iterator();"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); + assertTrue(source.indexOf("return this.i.next();") != -1); + assertTrue(source.matches(PatternMaker.make(": 52 */", "test(enumeration, \"test\");"))); + assertTrue(source.matches(PatternMaker.make(": 55 */", "System.out.println(\"end\");"))); + + assertTrue(source.matches(PatternMaker.make(": 67 */", "if (s1 == s2 && i == 5)"))); + + assertTrue(source.matches(PatternMaker.make(": 90 */", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "return (abc.equals(param2Object) || def.equals(param2Object) || str1.equals(param2Object) || str2.equals(param2Object));"))); + assertTrue(source.matches(PatternMaker.make(": 104 */", "System.out.println(\"end\");"))); + + assertTrue(source.indexOf("/* 111: 111 */") != -1); + + assertTrue(source.indexOf("{ ;") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile( + "1.5", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") + )); + } + + @Test + public void testJdk170AnonymousClass() throws Exception { + String internalClassName = "org/jd/core/test/AnonymousClass"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 21 */", "Object obj = new Object()"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "return \"toString() return \" + super.toString() + \" at \" + AnonymousClass.this.time;"))); + + assertTrue(source.matches(PatternMaker.make(": 39 */", "Enumeration e = new Enumeration()"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "Iterator i = AnonymousClass.this.list.iterator();"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "return (this.i.hasNext() && s1 == s2 && i1 > l1);"))); + + assertTrue(source.matches(PatternMaker.make(": 61 */", "final int i = s1.length();"))); + assertTrue(source.matches(PatternMaker.make(": 63 */", "System.out.println(\"2\" + new StringWrapper(123456L)"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "if (s1 == s2 && i == 5)"))); + assertTrue(source.matches(PatternMaker.make("/* 72: 0 */", "} + \"3\");"))); + + assertTrue(source.matches(PatternMaker.make(": 81 */", "final Object abc = \"abc\";"))); + assertTrue(source.matches(PatternMaker.make(": 82 */", "final Object def = \"def\";"))); + assertTrue(source.matches(PatternMaker.make(": 84 */", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 90 */", "Serializable serializable = new Serializable()"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "return (abc.equals(obj) || def.equals(obj) || ghi.equals(obj) || jkl.equals(obj));"))); + assertTrue(source.matches(PatternMaker.make(": 100 */", "return (abc.equals(obj) || def.equals(obj));"))); + assertTrue(source.matches(PatternMaker.make("/* 102: 0 */", "};"))); + + assertTrue(source.matches(PatternMaker.make(": 111 */", "this.l = l & 0x80L;"))); + + assertTrue(source.indexOf("{ ;") == -1); + assertTrue(source.indexOf("} ;") == -1); + assertTrue(source.indexOf("// Byte code:") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/annotation/Name", "package org.jd.core.test.annotation; public @interface Name {String value();}") + )); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaArrayTest.java b/src/test/java/org/jd/core/v1/JavaArrayTest.java new file mode 100644 index 00000000..af1d5329 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaArrayTest.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; + +public class JavaArrayTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk150Array() throws Exception { + String internalClassName = "org/jd/core/test/Array"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 13 */", "int[][] arrayOfInt1 = new int[1][];"))); + assertTrue(source.matches(PatternMaker.make(": 30 */", "int[][] arrayOfInt1 = { { 0, 1, 2"))); + + assertTrue(source.matches(PatternMaker.make(": 52 */", "testException2(new Exception[][]", "{ { new Exception(\"1\")"))); + + assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][] { { 1,"))); + + assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][] { { 1,"))); + assertTrue(source.matches(PatternMaker.make(": 75 */", "testInt3(new int[][][] { { { 0, 1"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170Array() throws Exception { + String internalClassName = "org/jd/core/test/Array"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 12 */", "int[] i1 = new int[1];"))); + assertTrue(source.matches(PatternMaker.make(": 13 */", "int[][] i2 = new int[1][];"))); + assertTrue(source.matches(PatternMaker.make(": 14 */", "int[][][] i3 = new int[1][][];"))); + assertTrue(source.matches(PatternMaker.make(": 15 */", "int[][][] i4 = new int[1][2][];"))); + assertTrue(source.matches(PatternMaker.make(": 22 */", "String[][][][] s5 = new String[1][2][][];"))); + + assertTrue(source.matches(PatternMaker.make(": 26 */", "byte[] b1 = { 1, 2 } ;"))); + assertTrue(source.matches(PatternMaker.make(": 27 */", "byte[][] b2 = { { 1, 2 } } ;"))); + assertTrue(source.matches(PatternMaker.make(": 28 */", "byte[][][][] b3 = { { { 3, 4 } } } ;"))); + + assertTrue(source.matches(PatternMaker.make(": 48 */", "testException1(new Exception[]", "{ new Exception(\"1\") } );"))); + + assertTrue(source.matches(PatternMaker.make(": 73 */", "testInt2(new int[][]", "{ { 1 } ,"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testInitializedArrayInTernaryOperator() throws Exception { + class InitializedArrayInTernaryOperator { + Class[] test0(int i) { + return (i == 0) ? new Class[] { Object.class } : null; + } + Class[] test2(int i) { + return (i == 0) ? new Class[] { Object.class, String.class, Number.class } : null; + } + Class[][] test3(int i) { + return (i == 0) ? new Class[][] { { Object.class }, { String.class, Number.class} } : null; + } + Class[] test4(int i) { + return (i == 0) ? null : new Class[] { Object.class }; + } + Class[] test5(int i) { + return (i == 0) ? null : new Class[] { Object.class, String.class, Number.class }; + } + Class[][] test6(int i) { + return (i == 0) ? null : new Class[][] { { Object.class }, { String.class, Number.class} }; + } + Class[] test7(int i) { + return (i == 0) ? new Class[] { Object.class } : new Class[] { String.class, Number.class }; + } + } + + String internalClassName = InitializedArrayInTernaryOperator.class.getName().replace('.', '/'); + String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 97 */", "return (i == 0) ? new Class[] { Object.class } : null;"))); + assertTrue(source.matches(PatternMaker.make(": 100 */", "return (i == 0) ? new Class[] { Object.class, String.class, Number.class } : null;"))); + assertTrue(source.matches(PatternMaker.make(": 103 */", "return (i == 0) ? new Class[][] { { Object.class }, { String.class, Number.class} } : null;"))); + assertTrue(source.matches(PatternMaker.make(": 106 */", "return (i == 0) ? null : new Class[] { Object.class };"))); + assertTrue(source.matches(PatternMaker.make(": 109 */", "return (i == 0) ? null : new Class[] { Object.class, String.class, Number.class };"))); + assertTrue(source.matches(PatternMaker.make(": 112 */", "return (i == 0) ? null : new Class[][] { { Object.class }, { String.class, Number.class} };"))); + assertTrue(source.matches(PatternMaker.make(": 115 */", "return (i == 0) ? new Class[] { Object.class } : new Class[] { String.class, Number.class };"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaAssertTest.java b/src/test/java/org/jd/core/v1/JavaAssertTest.java new file mode 100644 index 00000000..fbffee1f --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaAssertTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaAssertTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170Assert() throws Exception { + String internalClassName = "org/jd/core/test/Assert"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); + assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "assert i == 0 || i == 1;"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "assert i == 2 && i < 3;"))); + + assertTrue(source.matches(PatternMaker.make("/* 34: 34 */", "assert new BigDecimal(i) == BigDecimal.ONE;"))); + + assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk150Assert() throws Exception { + String internalClassName = "org/jd/core/test/Assert"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 16: 16 */", "assert false : \"false\";"))); + assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "assert paramInt == 0 || paramInt == 1;"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "assert paramInt == 2 && paramInt < 3;"))); + + assertTrue(source.matches(PatternMaker.make("/* 34: 34 */", "assert new BigDecimal(paramInt) == BigDecimal.ONE;"))); + + assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "assert check() : \"boom\";"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaBasicTest.java b/src/test/java/org/jd/core/v1/JavaBasicTest.java new file mode 100644 index 00000000..600b8dea --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaBasicTest.java @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.jd.core.v1.regex.PatternMaker; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaBasicTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("serialVersionUID = 9506606333927794L;") != -1); + assertTrue(source.indexOf(".indexOf('B');") != -1); + + assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "System.out.println(\"hello\");"))); + + assertTrue(source.indexOf("String str1 = \"3 == \" + (i + 1) + \" ?\";") != -1); + assertTrue(source.indexOf("String str2 = String.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); + assertTrue(source.indexOf("char c2 = '€';") != -1); + assertTrue(source.indexOf("char c3 = '\\'';") != -1); + assertTrue(source.indexOf("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');") != -1); + assertTrue(source.indexOf("Class class3 = String.class, class2 = class3, class1 = class2;") != -1); + assertTrue(source.matches(PatternMaker.make("Class class5 = doSomething(class6 = String.class, args1 = args2 = new String[], class4 = class5;"))); + assertTrue(source.matches(PatternMaker.make("int j = 1, k[] = {1, l[][] = {"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + + assertTrue(source.matches(PatternMaker.make(": 60 */", "return new String[] {s, s + '?'};"))); + + assertTrue(source.indexOf("if (this instanceof Object)") != -1); + + assertTrue(source.indexOf("int k = 50 / (25 + (i = 789));") != -1); + assertTrue(source.matches(PatternMaker.make(": 82 */", "k = i += 100;"))); + assertTrue(source.matches(PatternMaker.make(": 87 */", "i = ++this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "i = this.int78++;"))); + assertTrue(source.matches(PatternMaker.make(": 89 */", "i *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 91 */", "this.int78 = ++i;"))); + assertTrue(source.matches(PatternMaker.make(": 92 */", "this.int78 = i++;"))); + assertTrue(source.matches(PatternMaker.make(": 93 */", "this.int78 *= 10;"))); + assertTrue(source.matches(PatternMaker.make(": 95 */", "long34 = ++long12;"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "long34 = long12++;"))); + assertTrue(source.matches(PatternMaker.make(": 97 */", "long34 *= 10L;"))); + assertTrue(source.matches(PatternMaker.make(": 99 */", "i = (int)long12 + this.int78;"))); + assertTrue(source.matches(PatternMaker.make(": 101 */", "i = k ^ 0xFF;"))); + assertTrue(source.matches(PatternMaker.make(": 102 */", "i |= 0x7;"))); + + assertTrue(source.indexOf("int result;") != -1); + assertTrue(source.matches(PatternMaker.make(": 114 */", "result = 1;"))); + assertTrue(source.matches(PatternMaker.make(": 116 */", "int k = i;"))); + assertTrue(source.matches(PatternMaker.make(": 117 */", "result = k + 2;"))); + assertTrue(source.matches(PatternMaker.make(": 120 */", "result = this.short56;"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "return result;"))); + assertTrue(source.matches(PatternMaker.make(": 128 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make(": 130 */", "i = (int)(Basic.long12 + long12) + this.int78 + int78;"))); + + assertTrue(source.indexOf("public static native int read();") != -1); + + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); + + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + + assertTrue(source.indexOf("()") == -1); + assertTrue(source.indexOf("NaND") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170NoDebugInfoBasic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("System.out.println(\"hello\");"))); + + assertTrue(source.matches(PatternMaker.make("String str1 = \"3 == \" + (paramInt + 1) + \" ?\";"))); + assertTrue(source.indexOf("String str2 = String.valueOf(\"abc \\b \\f \\n \\r \\t \\\" \\007 def\");") != -1); + assertTrue(source.matches(PatternMaker.make("char c2 = '€';"))); + assertTrue(source.matches(PatternMaker.make("char c4 = c3 = c2 = c1 = Character.toUpperCase('x');"))); + assertTrue(source.matches(PatternMaker.make("Class clazz3 = String.class;"))); + assertTrue(source.matches(PatternMaker.make("Class clazz2 = clazz3;"))); + assertTrue(source.matches(PatternMaker.make("Class clazz1 = clazz2;"))); + assertTrue(source.indexOf("Class clazz5 = doSomething(clazz6 = String.class, arrayOfString1 = arrayOfString2 = new String[]") != -1); + + assertTrue(source.matches(PatternMaker.make("if (this instanceof Object)"))); + + assertTrue(source.matches(PatternMaker.make("this.int78 = 50 / (25 + (this.int78 = 789));"))); + + assertTrue(source.indexOf("protected static final Integer INTEGER_255 = new Integer(255);") != -1); + + assertTrue(source.indexOf("()") == -1); + assertTrue(source.indexOf("NaND") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170Constructors() throws Exception { + String internalClassName = "org/jd/core/test/Constructors"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 28 */", "this.short123 = 1;"))); + + assertTrue(source.matches(PatternMaker.make(": 32 */", "super(short56);"))); + assertTrue(source.matches(PatternMaker.make(": 33 */", "this.short123 = 2;"))); + + assertTrue(source.matches(PatternMaker.make(": 37 */", "this(short56);"))); + assertTrue(source.matches(PatternMaker.make(": 38 */", "this.int78 = int78;"))); + assertTrue(source.matches(PatternMaker.make(": 39 */", "this.short123 = 3;"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170Interface() throws Exception { + String internalClassName = "org/jd/core/test/Interface"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("public interface Interface", "extends Serializable"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk118Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make(": 128 */", "int int78 = getInt78(new Object[] { this }, (short)5);"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return String.valueOf(str) + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk142Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.4.2.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.4", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk901Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk1002Basic() throws Exception { + String internalClassName = "org/jd/core/test/Basic"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 18 */", "protected short short56 = 56;"))); + assertTrue(source.matches(PatternMaker.make(": 19 */", "protected int int78 = 78;"))); + assertTrue(source.matches(PatternMaker.make(": 43 */", "Class class3 = String.class, class2 = class3, class1 = class2;"))); + assertTrue(source.matches(PatternMaker.make("String stringNull = null;"))); + assertTrue(source.indexOf("public static native int read();") != -1); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "return str + str;"))); + assertTrue(source.matches(PatternMaker.make("/* 176: 176 */", "return str;"))); + assertTrue(source.matches(PatternMaker.make("/* 185: 185 */", "return ((Basic)objects[index]).int78;"))); + assertTrue(source.matches(PatternMaker.make("/* 188: 188 */", "protected static final Integer INTEGER_255 = new Integer(255);"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + // Test initializer block + public void testAnnotationUtils() throws Exception { + String internalClassName = "org/apache/commons/lang3/AnnotationUtils"; + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("setDefaultFullDetail(true);") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaEnumTest.java b/src/test/java/org/jd/core/v1/JavaEnumTest.java new file mode 100644 index 00000000..cc4a84f8 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaEnumTest.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; + +public class JavaEnumTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170Enum() throws Exception { + String internalClassName = "org/jd/core/test/Enum"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + + assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.indexOf("this.mass = mass;") != -1); + assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + + assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); + + assertTrue(source.indexOf("public static final enum") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk901Enum() throws Exception { + String internalClassName = "org/jd/core/test/Enum"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + + assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.indexOf("this.mass = mass;") != -1); + assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + + assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); + + assertTrue(source.indexOf("public static final enum") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk1002Enum() throws Exception { + String internalClassName = "org/jd/core/test/Enum"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 5 */", "SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;"))); + + assertTrue(source.matches(PatternMaker.make(": 9 */", "MERCURY(3.303E23D, 2439700.0D),"))); + assertTrue(source.matches(PatternMaker.make(": 17 */", "URANUS(8.686E25D, 2.5559E7D),"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "NEPTUNE(1.024E26D, 2.4746E7D);"))); + assertTrue(source.indexOf("this.mass = mass;") != -1); + assertTrue(source.matches(PatternMaker.make(": 27 */", "this.radius = radius;"))); + assertTrue(source.matches(PatternMaker.make(": 37 */", "return 6.673E-11D * this.mass / this.radius * this.radius;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "double earthWeight = Double.parseDouble(args[0]);"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "double mass = earthWeight / EARTH.surfaceGravity();"))); + assertTrue(source.matches(PatternMaker.make(": 51 */", "for (Planet p : values()) {"))); + assertTrue(source.matches(PatternMaker.make(": 52 */", "System.out.printf(\"Your weight on %s is %f%n\", new Object[]", "{ p, Double.valueOf(p.surfaceWeight(mass)) } );"))); + + assertTrue(source.matches(PatternMaker.make("enum EmptyEnum {}"))); + + assertTrue(source.indexOf("public static final enum") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaGenericTest.java b/src/test/java/org/jd/core/v1/JavaGenericTest.java new file mode 100644 index 00000000..75ceb195 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaGenericTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaGenericTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170GenericClass() throws Exception { + String internalClassName = "org/jd/core/test/GenericClass"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("public class GenericClass, T7 extends Map, T8 extends Map, T9 extends T8>") != -1); + assertTrue(source.indexOf("extends ArrayList") != -1); + assertTrue(source.indexOf("implements Serializable, Comparable") != -1); + + assertTrue(source.matches(PatternMaker.make("/* 26: 26 */", "public List> list1 = new ArrayList<>();"))); + assertTrue(source.indexOf("public List> list2;") != -1); + assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "list2 = new ArrayList<>();"))); + + assertTrue(source.indexOf("public void fromArrayToCollection(T[] a, Collection c)") != -1); + assertTrue(source.indexOf("public void copy(List dest, List src)") != -1); + assertTrue(source.indexOf("public List copy2(List dest, List src) throws InvalidParameterException, ClassCastException") != -1); + assertTrue(source.indexOf("public List print(List list) throws T2, InvalidParameterException") != -1); + + assertTrue(source.matches(PatternMaker.make(": 100 */", "return call(0);"))); + assertTrue(source.matches(PatternMaker.make(": 104 */", "return (T1)this;"))); + + assertTrue(source.indexOf("/* 104: 104 */") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile( + "1.7", + new JavaSourceFileObject(internalClassName, source), + new JavaSourceFileObject("org/jd/core/test/AnnotatedClass", "package org.jd.core.test; public class AnnotatedClass {}") + )); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaIfElseTest.java b/src/test/java/org/jd/core/v1/JavaIfElseTest.java new file mode 100644 index 00000000..9ac28215 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaIfElseTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaIfElseTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170IfElse() throws Exception { + String internalClassName = "org/jd/core/test/IfElse"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 12: 12 */", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("/* 22: 22 */", "if (\"abc\".isEmpty() && \"abc\".isEmpty())"))); + + assertTrue(source.matches(PatternMaker.make("/* 32: 32 */", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("/* 34: 0 */", "} else {"))); + + assertTrue(source.matches(PatternMaker.make("/* 44: 44 */", "if (this == null)"))); + assertTrue(source.matches(PatternMaker.make("/* 46: 46 */", "} else if (this == null) {"))); + assertTrue(source.matches(PatternMaker.make("/* 48: 0 */", "} else {"))); + + assertTrue(source.matches(PatternMaker.make("/* 58: 58 */", "if (i == 0)"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 60 */", "if (i == 1)"))); + + assertTrue(source.matches(PatternMaker.make("/* 71: 71 */", "if (i == System.currentTimeMillis())"))); + assertTrue(source.matches(PatternMaker.make("/* 73: 73 */", "} else if (i != System.currentTimeMillis()) {"))); + assertTrue(source.matches(PatternMaker.make("/* 75: 75 */", "} else if (i > System.currentTimeMillis()) {"))); + + assertTrue(source.matches(PatternMaker.make("/* 123: 123 */", "if (i == 4 && i == 5 && i == 6)"))); + + assertTrue(source.matches(PatternMaker.make("/* 135: 135 */", "if (i == 3 || i == 5 || i == 6)"))); + assertTrue(source.matches(PatternMaker.make("/* 137: 137 */", "} else if (i != 4 && i > 7 && i > 8) {"))); + assertTrue(source.matches(PatternMaker.make("/* 139: 0 */", "} else {"))); + + assertTrue(source.matches(PatternMaker.make("/* 148: 148 */", "if ((i == 1 && i == 2 && i == 3) || (i == 4 && i == 5 && i == 6) || (i == 7 && i == 8 && i == 9))"))); + assertTrue(source.matches(PatternMaker.make("/* 160: 160 */", "if ((i == 1 || i == 2 || i == 3) && (i == 4 || i == 5 || i == 6) && (i == 7 || i == 8 || i == 9))"))); + + assertTrue(source.matches(PatternMaker.make("/* 172: 172 */", "if ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))"))); + assertTrue(source.matches(PatternMaker.make("/* 184: 184 */", "if ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaInnerOuterClassTest.java b/src/test/java/org/jd/core/v1/JavaInnerOuterClassTest.java new file mode 100644 index 00000000..eb8905de --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaInnerOuterClassTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaInnerOuterClassTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170InnerOuterClass() throws Exception { + String internalClassName = "org/jd/core/test/OuterClass"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 10 */", "protected int outerField1 = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 11 */", "protected String[] outerField2 = { \"0\" };"))); + + assertTrue(source.indexOf("final int localVariable1 = param1;") != -1); + assertTrue(source.indexOf("final String[] localVariable2 = param2;") != -1); + + assertTrue(source.matches(PatternMaker.make(": 21 */", "InnerClass innerClass = new InnerClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 22 */", "innerClass.innerMethod(localVariable1, localVariable2);"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "StaticInnerClass staticInnerClass = new StaticInnerClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 25 */", "staticInnerClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 27 */", "InnerClass anonymousClass = new InnerClass(param1, param2)"))); + assertTrue(source.indexOf("public void innerMethod(int param1, String... param2)") != -1); + assertTrue(source.matches(PatternMaker.make(": 30 */", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 33 */", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 35 */", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 36 */", "this.innerField2 = localVariable2;"))); + + assertTrue(source.matches(PatternMaker.make(": 39 */", "anonymousClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 41 */", "StaticInnerClass staticAnonymousClass = new StaticInnerClass(param1, param2)"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 47 */", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 49 */", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 50 */", "this.innerField2 = localVariable2;"))); + + assertTrue(source.matches(PatternMaker.make(": 53 */", "staticAnonymousClass.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 55 */", "InnerEnum.A.innerMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make("/* 56: 0 */", "class LocalClass"))); + assertTrue(source.matches(PatternMaker.make(": 58 */", "protected int innerField1 = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "protected String[] innerField2 = { \"0\" } ;"))); + assertTrue(source.matches(PatternMaker.make(": 69 */", "this.innerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 70 */", "this.innerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "OuterClass.this.outerField1 = param1;"))); + assertTrue(source.matches(PatternMaker.make(": 73 */", "OuterClass.this.outerField2 = param2;"))); + assertTrue(source.matches(PatternMaker.make(": 75 */", "this.innerField1 = localVariable1;"))); + assertTrue(source.matches(PatternMaker.make(": 76 */", "this.innerField2 = localVariable2;"))); + assertTrue(source.matches(PatternMaker.make(": 94 */", "LocalClass localClass = new LocalClass(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 95 */", "localClass.localMethod(localVariable1, localVariable2);"))); + + assertTrue(source.matches(PatternMaker.make(": 114 */", "this(param1, param2);"))); + assertTrue(source.matches(PatternMaker.make(": 144 */", "this(param1, param2);"))); + + assertTrue(source.matches(PatternMaker.make(": 158 */", "A,", "B,", "C;"))); + assertTrue(source.indexOf("/* 182: 182 */") != -1); + + assertTrue(source.matches(PatternMaker.make("public class InnerInnerClass", "{", "}"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaLambdaTest.java b/src/test/java/org/jd/core/v1/JavaLambdaTest.java new file mode 100644 index 00000000..57869a30 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaLambdaTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaLambdaTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk180Lambda() throws Exception { + String internalClassName = "org/jd/core/test/Lambda"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 16 */", "list.forEach(System.out::println);"))); + assertTrue(source.matches(PatternMaker.make(": 20 */", "list.stream().filter(s -> (s != null)).forEach(s -> System.out.println(s));"))); + assertTrue(source.indexOf("Predicate filter = s -> (s.length() == length);") != -1); + assertTrue(source.indexOf("Consumer println = s -> System.out.println(s);") != -1); + assertTrue(source.matches(PatternMaker.make(": 27 */", "list.stream().filter(filter).forEach(println);"))); + assertTrue(source.matches(PatternMaker.make(": 31 */", "((Map)list.stream()"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", ".collect(Collectors.toMap(lambda -> Integer.valueOf(lambda.index), Function.identity())))"))); + assertTrue(source.matches(PatternMaker.make(": 33 */", ".forEach((key, value) ->"))); + assertTrue(source.matches(PatternMaker.make(": 48 */", "Thread thread = new Thread(() -> {"))); + assertTrue(source.matches(PatternMaker.make(": 58 */", "Consumer staticMethodReference = String::valueOf;"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "BiFunction methodReference = String::compareTo;"))); + assertTrue(source.matches(PatternMaker.make(": 60 */", "Supplier instanceMethodReference = s::toString;"))); + assertTrue(source.matches(PatternMaker.make(": 61 */", "Supplier constructorReference = String::new;"))); + assertTrue(source.matches(PatternMaker.make(": 65 */", "MethodType mtToString = MethodType.methodType(String.class);"))); + assertTrue(source.matches(PatternMaker.make(": 66 */", "MethodType mtSetter = MethodType.methodType(void.class, Object.class);"))); + assertTrue(source.matches(PatternMaker.make(": 67 */", "MethodType mtStringComparator = MethodType.methodType(int[].class, String.class, new Class[]", "{ String.class"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaLoopTest.java b/src/test/java/org/jd/core/v1/JavaLoopTest.java new file mode 100644 index 00000000..bb67e098 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaLoopTest.java @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; + +public class JavaLoopTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170While() throws Exception { + String internalClassName = "org/jd/core/test/While"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); + assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); + assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk901While() throws Exception { + String internalClassName = "org/jd/core/test/While"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); + assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); + assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk1002While() throws Exception { + String internalClassName = "org/jd/core/test/While"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 15 */", "while (i-- > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "while (i0 > 20)"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 128: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 158: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 232 */", "while (++i < 10)"))); + assertTrue(source.indexOf("while (i == 4 && i == 5 && i == 6)") != -1); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4))") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4))") != -1); + assertFalse(source.matches(PatternMaker.make("[ 348: 0 */", "default:"))); + assertFalse(source.matches(PatternMaker.make("[ 350: 348 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 404: 404 */", "System.out.println(\"a\");"))); + assertTrue(source.matches(PatternMaker.make("/* 431: 431 */", "System.out.println(\"a\");"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170DoWhile() throws Exception { + String internalClassName = "org/jd/core/test/DoWhile"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk901DoWhile() throws Exception { + String internalClassName = "org/jd/core/test/DoWhile"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-9.0.1.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk1002DoWhile() throws Exception { + String internalClassName = "org/jd/core/test/DoWhile"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-10.0.2.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 24 */", "} while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 32 */", "} while (this == null);"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "++i;"))); + assertTrue(source.matches(PatternMaker.make(": 46 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "while (i0 < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 77 */", "i1--;"))); + assertTrue(source.matches(PatternMaker.make(": 79 */", "while (i1 > 0);"))); + assertTrue(source.matches(PatternMaker.make(": 98 */", "while (--i > 0.0F);"))); + assertTrue(source.matches(PatternMaker.make(": 108 */", "while (i-- > 0.0F);"))); + assertTrue(source.indexOf("while ((i == 1 || (i == 5 && i == 6 && i == 7) || i == 8 || (i == 9 && i == 10 && i == 11)) && (i == 4 || i % 200 > 50) && (i > 3 || i > 4));") != -1); + assertTrue(source.indexOf("while ((i == 1 && (i == 5 || i == 6 || i == 7) && i == 8 && (i == 9 || i == 10 || i == 11)) || (i == 4 && i % 200 > 50) || (i > 3 && i > 4));") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170BreakContinue() throws Exception { + String internalClassName = "org/jd/core/test/BreakContinue"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "if (i == 1)"))); + assertTrue(source.matches(PatternMaker.make("/* 16: 0 */", "continue;"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 18 */", "if (i == 2)"))); + assertTrue(source.matches(PatternMaker.make("/* 19: 0 */", "continue;"))); + + assertTrue(source.matches(PatternMaker.make("/* 31: 31 */", "label18: while (i > 1)"))); + assertTrue(source.matches(PatternMaker.make("/* 37: 0 */", "continue label18;"))); + assertTrue(source.matches(PatternMaker.make("/* 40: 0 */", "break label18;"))); + + assertTrue(source.matches(PatternMaker.make("/* 54: 54 */", "label17: while (i > 1)"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 63: 0 */", "continue label17;"))); + + assertTrue(source.matches(PatternMaker.make("/* 78: 0 */", "label13:"))); + assertTrue(source.matches(PatternMaker.make("/* 83: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 86: 0 */", "break label13;"))); + + assertTrue(source.matches(PatternMaker.make("/* 101: 0 */", "label15:", "do {"))); + assertTrue(source.matches(PatternMaker.make("/* 106: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 109: 0 */", "break label15;"))); + + assertTrue(source.matches(PatternMaker.make("/* 123: 0 */", "label24:", "do {"))); + assertTrue(source.matches(PatternMaker.make("/* 133: 0 */", "continue label24;"))); + assertTrue(source.matches(PatternMaker.make("/* 135: 0 */", "break label24;"))); + assertTrue(source.matches(PatternMaker.make("/* 138: 0 */", "break label23;"))); + + assertTrue(source.matches(PatternMaker.make("/* 155: 0 */", "label16:", "do {"))); + assertTrue(source.matches(PatternMaker.make("/* 162: 0 */", "break label16;"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170For() throws Exception { + String internalClassName = "org/jd/core/test/For"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 42 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 44 */", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 54 */", "for (; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 64 */", "for (int i = 0;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 72 */", "for (;; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 80 */", "for (int i = 0; i < 10;)"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 96 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("/* 104: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 112 */", "for (int i = 0, j = i, size = 10; i < size; j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 122 */", "int i = 0, j = i, size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 123 */", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "j += ++i)"))); + assertTrue(source.matches(PatternMaker.make(": 134 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 135 */", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 136 */", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 137 */", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 138 */", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 139 */", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 149 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make(": 151 */", "int j = i;"))); + assertTrue(source.matches(PatternMaker.make(": 153 */", "int size = 10;"))); + assertTrue(source.matches(PatternMaker.make(": 155 */", "for (; i < size;"))); + assertTrue(source.matches(PatternMaker.make(": 157 */", "i++,"))); + assertTrue(source.matches(PatternMaker.make(": 159 */", "j += i)"))); + assertTrue(source.matches(PatternMaker.make(": 169 */", "for (int i = 0; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 177 */", "for (; i < 10; i++);"))); + assertTrue(source.matches(PatternMaker.make(": 185 */", "for (int i = 0;; i++);"))); + assertTrue(source.matches(PatternMaker.make("/* 190: 0 */", "while (true)"))); + assertTrue(source.matches(PatternMaker.make(": 191 */", "i++;"))); + assertTrue(source.matches(PatternMaker.make(": 197 */", "for (int i = 0; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 203 */", "for (int[] i = { 0 }; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 209 */", "for (int i = 0, j = i, k = i; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 215 */", "for (int[] i = { 0 }, j = i, k = j; i.length < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 221 */", "for (int i = 0, j[] = { 1 }; i < 10;);"))); + assertTrue(source.matches(PatternMaker.make(": 227 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 233 */", "int i = 0;"))); + assertTrue(source.matches(PatternMaker.make("/* 234: 0 */", "while (true);"))); + assertTrue(source.matches(PatternMaker.make(": 245 */", "for (int i = 0, j = i, size = 10; i < size; j += ++i);"))); + assertTrue(source.matches(PatternMaker.make("/* 253: 0 */", "while (true) {"))); + assertTrue(source.matches(PatternMaker.make(": 264 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make(": 389 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 403 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); + + assertTrue(source.indexOf("/* 524: 524 */") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170NoDebugInfoFor() throws Exception { + String internalClassName = "org/jd/core/test/For"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0-no-debug-info.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make("for (byte b = 0;; b++)"))); + assertTrue(source.matches(PatternMaker.make("for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); + assertTrue(source.matches(PatternMaker.make("for (paramInt = 0; paramInt < 10; paramInt++)"))); + assertTrue(source.matches(PatternMaker.make("for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("for (String str : paramArrayOfString)"))); + assertTrue(source.matches(PatternMaker.make("for (String str : paramList)"))); + + // Recompile decompiled source code and check errors + //assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk150For() throws Exception { + String internalClassName = "org/jd/core/test/For"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.5.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 20 */", "for (byte b = 0; b < 10; b++)"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (paramInt < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 273 */", "for (paramInt = 0; paramInt < 10; paramInt++)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int i : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 349 */", "while (b < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String str : paramArrayOfString)"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String str : paramList)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "for (byte b = 0; b < 3; b++)"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk160For() throws Exception { + String internalClassName = "org/jd/core/test/For"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.6.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 20 */", "for (int i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 273 */", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do {"))); + assertTrue(source.matches(PatternMaker.make(": 349 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.6", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testIbmJ9For() throws Exception { + String internalClassName = "org/jd/core/test/For"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-ibm-j9_vm.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 88 */", "while (i < 10)"))); + assertTrue(source.matches(PatternMaker.make(": 273 */", "for (i = 0; i < 10; i++)"))); + assertTrue(source.matches(PatternMaker.make(": 310 */", "for (int j : new int[] { 4 })"))); + assertTrue(source.matches(PatternMaker.make("/* 347: 0 */", "do"))); + assertTrue(source.matches(PatternMaker.make(": 349 */", "while (i < 10);"))); + assertTrue(source.matches(PatternMaker.make(": 385 */", "for (String s : array)"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "for (String s : list)"))); + assertTrue(source.matches(PatternMaker.make(": 411 */", "Iterator> iterator = Arrays.>asList(getClass().getInterfaces()).iterator()"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "for (int i = 0; i < 3; i++)"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaSwitchTest.java b/src/test/java/org/jd/core/v1/JavaSwitchTest.java new file mode 100644 index 00000000..f2fa604a --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaSwitchTest.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; + +public class JavaSwitchTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170Switch() throws Exception { + String internalClassName = "org/jd/core/test/Switch"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 15: 15 */", "switch (i)"))); + assertTrue(source.matches(PatternMaker.make("/* 16: 0 */", "case 0:"))); + assertTrue(source.matches(PatternMaker.make("/* 17: 17 */", "System.out.println(\"0\");"))); + assertTrue(source.matches(PatternMaker.make("/* 18: 0 */", "break;"))); + + assertTrue(source.matches(PatternMaker.make("/* 34: 0 */", "case 0:"))); + assertTrue(source.matches(PatternMaker.make("/* 35: 35 */", "System.out.println(\"0\");"))); + assertTrue(source.matches(PatternMaker.make("/* 36: 0 */", "case 1:"))); + + assertTrue(source.matches(PatternMaker.make("/* 56: 0 */", "default:"))); + + assertTrue(source.matches(PatternMaker.make("/* 110: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 111: 0 */", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("/* 112: 112 */", "System.out.println(\"1\");"))); + assertTrue(source.matches(PatternMaker.make("/* 113: 113 */", "throw new RuntimeException(\"boom\");"))); + + assertTrue(source.matches(PatternMaker.make("/* 134: 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make("/* 171: 0 */", "case 3:"))); + assertTrue(source.matches(PatternMaker.make("/* 172: 0 */", "case 4:"))); + assertTrue(source.matches(PatternMaker.make("/* 173: 173 */", "System.out.println(\"3 or 4\");"))); + assertTrue(source.matches(PatternMaker.make("/* 174: 0 */", "break;"))); + + assertTrue(source.matches(PatternMaker.make("/* 265: 0 */", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("/* 266: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 267: 0 */", "default:"))); + + assertTrue(source.matches(PatternMaker.make("/* 283: 0 */", "case 1:"))); + assertTrue(source.matches(PatternMaker.make("/* 284: 0 */", "case 2:"))); + assertTrue(source.matches(PatternMaker.make("/* 285: 0 */", "case 3:"))); + assertTrue(source.matches(PatternMaker.make("/* 286: 0 */", "break;"))); + assertTrue(source.matches(PatternMaker.make("/* 288: 0 */", "default:"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170AdvancedSwitch() throws Exception { + String internalClassName = "org/jd/core/test/AdvancedSwitch"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make("/* 13: 13 */", "A,", "B,", "C;"))); + + assertTrue(source.matches(PatternMaker.make("/* 19: 19 */", "switch (te)"))); + assertTrue(source.matches(PatternMaker.make("/* 20: 0 */", "case A:"))); + assertTrue(source.matches(PatternMaker.make("/* 22: 0 */", "case B:"))); + assertTrue(source.matches(PatternMaker.make("/* 25: 0 */", "case C:"))); + + assertTrue(source.matches(PatternMaker.make("/* 39: 0 */", "case A:"))); + assertTrue(source.matches(PatternMaker.make("/* 40: 0 */", "case B:"))); + assertTrue(source.matches(PatternMaker.make("/* 41: 41 */", "System.out.println(\"A or B\");"))); + + assertTrue(source.matches(PatternMaker.make("/* 56: 56 */", "switch (str)"))); + assertTrue(source.matches(PatternMaker.make("/* 57: 0 */", "case \"One\":"))); + assertTrue(source.matches(PatternMaker.make("/* 58: 58 */", "System.out.println(1);"))); + + assertTrue(source.matches(PatternMaker.make("/* 78: 0 */", "case \"One\":"))); + assertTrue(source.matches(PatternMaker.make("/* 79: 0 */", "case \"POe\":"))); + assertTrue(source.matches(PatternMaker.make("/* 80: 80 */", "System.out.println(\"'One' or 'POe'\");"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testEclipseJavaCompiler321Switch() throws Exception { + String internalClassName = "org/jd/core/test/Switch"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("/* 239: 239 */") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testEclipseJavaCompiler3130Switch() throws Exception { + String internalClassName = "org/jd/core/test/Switch"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("/* 239: 239 */") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + // Test switch-enum in an other switch-enum + public void testBstMutationResult() throws Exception { + String internalClassName = "com/google/common/collect/BstMutationResult"; + Class mainClass = com.google.common.collect.Collections2.class; + InputStream is = new FileInputStream(Paths.get(mainClass.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile()); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("N resultLeft, resultRight;") != -1); + assertTrue(source.indexOf("assert false;") == -1); + assertTrue(source.matches(PatternMaker.make("/* 131:", "resultLeft = liftOriginalRoot.childOrNull(BstSide.LEFT);"))); + assertTrue(source.matches(PatternMaker.make("/* 134:", "case LEFT:"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaSynchronizedBlockTest.java b/src/test/java/org/jd/core/v1/JavaSynchronizedBlockTest.java new file mode 100644 index 00000000..52cba281 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaSynchronizedBlockTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaSynchronizedBlockTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170Synchronised() throws Exception { + String internalClassName = "org/jd/core/test/Synchronized"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 11 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 13 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 15 */", "return 2;"))); + + assertTrue(source.matches(PatternMaker.make(": 20 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 22 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 23 */", "return 2;"))); + + assertTrue(source.matches(PatternMaker.make(": 29 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 31 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 73 */", "synchronized (paramStringBuilder)"))); + assertTrue(source.matches(PatternMaker.make(": 75 */", "inSynchronized();"))); + assertTrue(source.matches(PatternMaker.make(": 76 */", "throw new RuntimeException();"))); + + assertTrue(source.matches(PatternMaker.make(": 95 */", "synchronized (s)"))); + assertTrue(source.matches(PatternMaker.make(": 97 */", "return subContentEquals(s);"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaTernaryOperatorTest.java b/src/test/java/org/jd/core/v1/JavaTernaryOperatorTest.java new file mode 100644 index 00000000..22b0dced --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaTernaryOperatorTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaTernaryOperatorTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk118TernaryOperator() throws Exception { + String internalClassName = "org/jd/core/test/TernaryOperator"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str ="))); + assertTrue(source.matches(PatternMaker.make(": 14 */", "(s == null) ?"))); + assertTrue(source.matches(PatternMaker.make(": 15 */", "\"1\""))); + assertTrue(source.matches(PatternMaker.make(": 16 */", "\"2\";"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); + assertTrue(source.matches(PatternMaker.make(": 34 */", "return !(s != s || time < time);"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 60 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 71 */", "if ((s1 == null) ? false : (s1.length() > 0))"))); + assertTrue(source.matches(PatternMaker.make(": 82 */", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 126 */", "if (s1 == null && false)"))); + assertTrue(source.matches(PatternMaker.make(": 137 */", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170TernaryOperator() throws Exception { + String internalClassName = "org/jd/core/test/TernaryOperator"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + String source = decompile(loader, new PlainTextPrinter(), internalClassName); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 13 */", "this.str = (s == null) ? \"1\" : \"2\";"))); + assertTrue(source.matches(PatternMaker.make(": 24 */", "s = (s == null) ? ((s == null) ? \"1\" : \"2\") : ((s == null) ? \"3\" : \"4\");"))); + assertTrue(source.matches(PatternMaker.make(": 34 */", "return (s == s && time >= time);"))); + assertTrue(source.matches(PatternMaker.make(": 40 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 60 */", "if ((s1 == null) ? (s2 == null) : s1.equals(s2))"))); + assertTrue(source.matches(PatternMaker.make(": 71 */", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 82 */", "if (s1 != null && s1.length() > 0)"))); + assertTrue(source.matches(PatternMaker.make(": 126 */", "if (s1 == null);"))); + assertTrue(source.matches(PatternMaker.make(": 137 */", "if (s1 == s2 && ((s1 == null) ? (s2 == null) : s1.equals(s2)) && s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 148 */", "if (s1 == s2 || ((s1 == null) ? (s2 == null) : s1.equals(s2)) || s1 == s2)"))); + assertTrue(source.matches(PatternMaker.make(": 157 */", "return Short.toString((short)((this == null) ? 1 : 2));"))); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} diff --git a/src/test/java/org/jd/core/v1/JavaTryCatchFinallyTest.java b/src/test/java/org/jd/core/v1/JavaTryCatchFinallyTest.java new file mode 100644 index 00000000..76130389 --- /dev/null +++ b/src/test/java/org/jd/core/v1/JavaTryCatchFinallyTest.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1; + +import junit.framework.TestCase; +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.printer.Printer; +import org.jd.core.v1.compiler.CompilerUtil; +import org.jd.core.v1.compiler.JavaSourceFileObject; +import org.jd.core.v1.loader.ClassPathLoader; +import org.jd.core.v1.loader.ZipLoader; +import org.jd.core.v1.model.message.Message; +import org.jd.core.v1.printer.PlainTextPrinter; +import org.jd.core.v1.regex.PatternMaker; +import org.jd.core.v1.service.converter.classfiletojavasyntax.ClassFileToJavaSyntaxProcessor; +import org.jd.core.v1.service.deserializer.classfile.DeserializeClassFileProcessor; +import org.jd.core.v1.service.fragmenter.javasyntaxtojavafragment.JavaSyntaxToJavaFragmentProcessor; +import org.jd.core.v1.service.layouter.LayoutFragmentProcessor; +import org.jd.core.v1.service.tokenizer.javafragmenttotoken.JavaFragmentToTokenProcessor; +import org.jd.core.v1.service.writer.WriteTokenProcessor; +import org.junit.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; + +public class JavaTryCatchFinallyTest extends TestCase { + protected DeserializeClassFileProcessor deserializer = new DeserializeClassFileProcessor(); + protected ClassFileToJavaSyntaxProcessor converter = new ClassFileToJavaSyntaxProcessor(); + protected JavaSyntaxToJavaFragmentProcessor fragmenter = new JavaSyntaxToJavaFragmentProcessor(); + protected LayoutFragmentProcessor layouter = new LayoutFragmentProcessor(); + //protected TestTokenizeJavaFragmentProcessor tokenizer = new TestTokenizeJavaFragmentProcessor(); + protected JavaFragmentToTokenProcessor tokenizer = new JavaFragmentToTokenProcessor(); + protected WriteTokenProcessor writer = new WriteTokenProcessor(); + + @Test + public void testJdk170TryWithResources() throws Exception { + String internalClassName = "org/jd/core/test/TryWithResources"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); + + assertTrue(source.matches(PatternMaker.make(": 49 */", "try (FileInputStream input = new FileInputStream(path))"))); + assertTrue(source.matches(PatternMaker.make(": 57 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "System.out.println(\"finally\");"))); + + assertTrue(source.matches(PatternMaker.make(": 121 */", "try(FileInputStream input = new FileInputStream(pathIn);"))); + assertTrue(source.matches(PatternMaker.make(": 122 */", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); + assertTrue(source.matches(PatternMaker.make(": 123 */", "FileOutputStream output = new FileOutputStream(pathOut);"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); + assertTrue(source.matches(PatternMaker.make(": 132 */", "if (data == -7)"))); + assertTrue(source.matches(PatternMaker.make(": 133 */", "return 1;"))); + assertTrue(source.matches(PatternMaker.make(": 142 */", "return 2;"))); + assertTrue(source.matches(PatternMaker.make(": 144 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 150 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 152 */", "System.out.println(\"finally, before loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 156 */", "System.out.println(\"finally, after loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 159 */", "System.out.println(\"finally\");"))); + assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); + + assertTrue(source.indexOf("/* 162: 162 */") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk180TryWithResources() throws Exception { + String internalClassName = "org/jd/core/test/TryWithResources"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.8.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.matches(PatternMaker.make(": 12 */", "try (FileInputStream input = new FileInputStream(path))"))); + + assertTrue(source.matches(PatternMaker.make(": 49 */", "try (FileInputStream input = new FileInputStream(path))"))); + assertTrue(source.matches(PatternMaker.make(": 57 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 59 */", "System.out.println(\"finally\");"))); + + assertTrue(source.matches(PatternMaker.make(": 121 */", "try(FileInputStream input = new FileInputStream(pathIn);"))); + assertTrue(source.matches(PatternMaker.make(": 122 */", "BufferedInputStream bufferedInput = new BufferedInputStream(input);"))); + assertTrue(source.matches(PatternMaker.make(": 123 */", "FileOutputStream output = new FileOutputStream(pathOut);"))); + assertTrue(source.matches(PatternMaker.make(": 124 */", "BufferedOutputStream bufferedOutput = new BufferedOutputStream(output))"))); + assertTrue(source.matches(PatternMaker.make(": 132 */", "if (data == -7)"))); + assertTrue(source.matches(PatternMaker.make(": 133 */", "return 1;"))); + assertTrue(source.matches(PatternMaker.make(": 142 */", "return 2;"))); + assertTrue(source.matches(PatternMaker.make(": 144 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 150 */", "e.printStackTrace();"))); + assertTrue(source.matches(PatternMaker.make(": 152 */", "System.out.println(\"finally, before loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 156 */", "System.out.println(\"finally, after loop\");"))); + assertTrue(source.matches(PatternMaker.make(": 159 */", "System.out.println(\"finally\");"))); + assertTrue(source.matches(PatternMaker.make(": 162 */", "return 3;"))); + + assertTrue(source.indexOf("/* 162: 162 */") != -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testEclipseJavaCompiler321TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.2.1.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("/* 45: 45 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); + + // TODO assertTrue(source.matches(PatternMaker.make("/* 217:", "inCatch1();"))); + + assertTrue(source.indexOf("/* 888: 888 */") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + + System.out.println(JavaTryCatchFinallyTest.class.getProtectionDomain().getCodeSource().getLocation().getPath()); + System.out.println(System.getProperty("java.class.path")); + } + + @Test + public void testEclipseJavaCompiler370TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); + assertTrue(source.indexOf("/* 400: 0] inFinally();") == -1); + + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); + + assertTrue(source.indexOf("/* 888: 888 */") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testEclipseJavaCompiler3130TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-eclipse-java-compiler-3.13.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("catch (RuntimeException runtimeException)") != -1); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); + + assertTrue(source.indexOf("/* 888: 888 */") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.5", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk118TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.1.8.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); + + assertTrue(source.indexOf("/* 902: 902 */") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk131TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.3.1.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); + + assertTrue(source.indexOf("/* 902: 902 */") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.3", new JavaSourceFileObject(internalClassName, source))); + } + + @Test + public void testJdk170TryCatchFinally() throws Exception { + String internalClassName = "org/jd/core/test/TryCatchFinally"; + InputStream is = this.getClass().getResourceAsStream("/zip/data-java-jdk-1.7.0.zip"); + Loader loader = new ZipLoader(is); + Map configuration = Collections.singletonMap("realignLineNumbers", Boolean.TRUE); + String source = decompile(loader, new PlainTextPrinter(), internalClassName, configuration); + + // Check decompiled source code + assertTrue(source.indexOf("catch (RuntimeException runtimeexception)") != -1); + assertTrue(source.matches(PatternMaker.make("/* 48: 48 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make("/* 60: 0 */", "return;"))); + + assertTrue(source.matches(PatternMaker.make(": 166 */", "return System.currentTimeMillis();"))); + + assertTrue(source.matches(PatternMaker.make(": 192 */", "catch (RuntimeException e) {}"))); + assertTrue(source.matches(PatternMaker.make("/* 204: 0 */", "finally {}"))); + + assertTrue(source.matches(PatternMaker.make(": 393 */", "inCatch1();"))); + assertTrue(source.matches(PatternMaker.make(": 395 */", "inCatch2();"))); + assertTrue(source.matches(PatternMaker.make(": 397 */", "inCatch3();"))); + assertTrue(source.matches(PatternMaker.make(": 399 */", "inFinally();"))); + + assertTrue(source.matches(PatternMaker.make(": 424 */", "inTry();"))); + assertTrue(source.matches(PatternMaker.make(": 427 */", "inFinally();"))); + assertTrue(source.matches(PatternMaker.make(": 431 */", "inTryA();"))); + assertTrue(source.matches(PatternMaker.make(": 434 */", "inFinallyA();"))); + assertTrue(source.matches(PatternMaker.make(": 439 */", "inTryC();"))); + assertTrue(source.matches(PatternMaker.make(": 442 */", "inFinallyC();"))); + assertTrue(source.matches(PatternMaker.make(": 445 */", "inFinally();"))); + + assertTrue(source.indexOf("/* 902: 902 */") != -1); + + assertTrue(source.indexOf("long l = System.currentTimeMillis(); return l;") == -1); + assertTrue(source.indexOf("catch (RuntimeException null)") == -1); + assertTrue(source.indexOf("Object object;") == -1); + assertTrue(source.indexOf("RuntimeException runtimeexception4;") == -1); + assertTrue(source.indexOf("Exception exception8;") == -1); + + // Recompile decompiled source code and check errors + assertTrue(CompilerUtil.compile("1.7", new JavaSourceFileObject(internalClassName, source))); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName) throws Exception { + return decompile(loader, printer, internalTypeName, Collections.emptyMap()); + } + + protected String decompile(Loader loader, Printer printer, String internalTypeName, Map configuration) throws Exception { + Message message = new Message(); + message.setHeader("loader", loader); + message.setHeader("printer", printer); + message.setHeader("mainInternalTypeName", internalTypeName); + message.setHeader("configuration", configuration); + + deserializer.process(message); + converter.process(message); + fragmenter.process(message); + layouter.process(message); + tokenizer.process(message); + writer.process(message); + + String source = printer.toString(); + + printSource(source); + + assertTrue(source.indexOf("// Byte code:") == -1); + + return source; + } + + protected void printSource(String source) { + System.out.println("- - - - - - - - "); + System.out.println(source); + System.out.println("- - - - - - - - "); + } +} From d369927c26ff0608b621ff8a06f3f20ab6598d2d Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 3 Feb 2020 22:27:10 +0100 Subject: [PATCH 167/211] Minor updates --- .../classfiletojavasyntax/util/StatementMaker.java | 2 ++ src/test/java/org/jd/core/v1/JavaArrayTest.java | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java index 801e3394..d792dac6 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StatementMaker.java @@ -328,6 +328,8 @@ protected Expression makeExpression(WatchDog watchdog, BasicBlock basicBlock, St // Pattern matched -> Multi-assignment statements.removeLast(); expression = boe; + } else if (expression.getClass() == NewArray.class) { + expression = NewArrayMaker.make(statements, (NewArray)expression); } } } diff --git a/src/test/java/org/jd/core/v1/JavaArrayTest.java b/src/test/java/org/jd/core/v1/JavaArrayTest.java index af1d5329..8d8db203 100644 --- a/src/test/java/org/jd/core/v1/JavaArrayTest.java +++ b/src/test/java/org/jd/core/v1/JavaArrayTest.java @@ -118,13 +118,13 @@ Class[] test7(int i) { String source = decompile(new ClassPathLoader(), new PlainTextPrinter(), internalClassName); // Check decompiled source code - assertTrue(source.matches(PatternMaker.make(": 97 */", "return (i == 0) ? new Class[] { Object.class } : null;"))); - assertTrue(source.matches(PatternMaker.make(": 100 */", "return (i == 0) ? new Class[] { Object.class, String.class, Number.class } : null;"))); - assertTrue(source.matches(PatternMaker.make(": 103 */", "return (i == 0) ? new Class[][] { { Object.class }, { String.class, Number.class} } : null;"))); - assertTrue(source.matches(PatternMaker.make(": 106 */", "return (i == 0) ? null : new Class[] { Object.class };"))); - assertTrue(source.matches(PatternMaker.make(": 109 */", "return (i == 0) ? null : new Class[] { Object.class, String.class, Number.class };"))); - assertTrue(source.matches(PatternMaker.make(": 112 */", "return (i == 0) ? null : new Class[][] { { Object.class }, { String.class, Number.class} };"))); - assertTrue(source.matches(PatternMaker.make(": 115 */", "return (i == 0) ? new Class[] { Object.class } : new Class[] { String.class, Number.class };"))); + assertTrue(source.matches(PatternMaker.make(": 95 */", "return (i == 0) ? new Class[] { Object.class } : null;"))); + assertTrue(source.matches(PatternMaker.make(": 98 */", "return (i == 0) ? new Class[] { Object.class, String.class, Number.class } : null;"))); + assertTrue(source.matches(PatternMaker.make(": 101 */", "return (i == 0) ? new Class[][] { { Object.class }, { String.class, Number.class} } : (Class[][])null;"))); + assertTrue(source.matches(PatternMaker.make(": 104 */", "return (i == 0) ? null : new Class[] { Object.class };"))); + assertTrue(source.matches(PatternMaker.make(": 107 */", "return (i == 0) ? null : new Class[] { Object.class, String.class, Number.class };"))); + assertTrue(source.matches(PatternMaker.make(": 110 */", "return (i == 0) ? (Class[][])null : new Class[][] { { Object.class }, { String.class, Number.class} };"))); + assertTrue(source.matches(PatternMaker.make(": 113 */", "return (i == 0) ? new Class[] { Object.class } : new Class[] { String.class, Number.class };"))); // Recompile decompiled source code and check errors assertTrue(CompilerUtil.compile("1.8", new JavaSourceFileObject(internalClassName, source))); From 1a880f704b5c063c2d2bcdf98f8ffbc0a90a3f34 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 3 Feb 2020 22:30:24 +0100 Subject: [PATCH 168/211] Update test --- src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java index c129e3ee..03532a90 100644 --- a/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java +++ b/src/test/java/org/jd/core/v1/JarFileToJavaSourceTest.java @@ -157,9 +157,7 @@ protected void test(InputStream inputStream) throws Exception { if (path.endsWith(".class") && (path.indexOf('$') == -1)) { String internalTypeName = path.substring(0, path.length() - 6); // 6 = ".class".length() - // TODO DEBUG if (!internalTypeName.endsWith("/Rule")) continue; - //if (!internalTypeName.endsWith("/TypeUtils")) continue; - if (!internalTypeName.endsWith("/Parameterized")) continue; + // TODO DEBUG if (!internalTypeName.endsWith("/Debug")) continue; message.setHeader("mainInternalTypeName", internalTypeName); printer.init(); From 55c4460b51753f76100ba1ba08880038d1181103 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 3 Feb 2020 22:47:24 +0100 Subject: [PATCH 169/211] Update JD collection class --- src/main/java/org/jd/core/v1/util/Base.java | 2 +- src/main/java/org/jd/core/v1/util/DefaultList.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jd/core/v1/util/Base.java b/src/main/java/org/jd/core/v1/util/Base.java index 21cd8e5b..9fa7e935 100644 --- a/src/main/java/org/jd/core/v1/util/Base.java +++ b/src/main/java/org/jd/core/v1/util/Base.java @@ -25,7 +25,7 @@ default T getLast() { } default DefaultList getList() { - return (DefaultList)this; + throw new UnsupportedOperationException(); } default int size() { diff --git a/src/main/java/org/jd/core/v1/util/DefaultList.java b/src/main/java/org/jd/core/v1/util/DefaultList.java index 48ca424c..831cf4c9 100644 --- a/src/main/java/org/jd/core/v1/util/DefaultList.java +++ b/src/main/java/org/jd/core/v1/util/DefaultList.java @@ -66,6 +66,10 @@ public boolean isList() { return true; } + public DefaultList getList() { + return this; + } + public static DefaultList emptyList() { return EMPTY_LIST; } From 52dd723016371f83c8aeba45aed22339018dbbe3 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sat, 8 Feb 2020 12:30:33 +0100 Subject: [PATCH 170/211] Refactoring to simplify AST exploration --- .../javasyntax/AbstractJavaSyntaxVisitor.java | 8 +- .../declaration/BaseMemberDeclaration.java | 1 + .../declaration/ClassDeclaration.java | 3 + .../ExpressionVariableInitializer.java | 4 + .../declaration/VariableInitializer.java | 8 + .../AbstractNopExpressionVisitor.java | 1 + .../expression/ArrayExpression.java | 4 + .../javasyntax/expression/BaseExpression.java | 47 ++ .../expression/BinaryOperatorExpression.java | 16 +- .../expression/BooleanExpression.java | 3 + .../javasyntax/expression/CastExpression.java | 4 + .../ConstructorInvocationExpression.java | 4 + .../ConstructorReferenceExpression.java | 1 + .../expression/DoubleConstantExpression.java | 6 +- .../EnumConstantReferenceExpression.java | 1 + .../expression/ExpressionVisitor.java | 1 + .../expression/FieldReferenceExpression.java | 6 + .../expression/FloatConstantExpression.java | 5 +- .../expression/InstanceOfExpression.java | 1 + .../expression/IntegerConstantExpression.java | 16 +- .../LambdaFormalParametersExpression.java | 20 +- .../LambdaIdentifiersExpression.java | 16 +- .../expression/LengthExpression.java | 4 + .../LocalVariableReferenceExpression.java | 4 + .../expression/LongConstantExpression.java | 6 +- .../MethodInvocationExpression.java | 4 + .../expression/MethodReferenceExpression.java | 3 + .../model/javasyntax/expression/NewArray.java | 4 + .../javasyntax/expression/NewExpression.java | 5 + .../expression/NewInitializedArray.java | 3 + .../javasyntax/expression/NoExpression.java | 28 + .../javasyntax/expression/NullExpression.java | 3 + .../ObjectTypeReferenceExpression.java | 3 + .../expression/ParenthesesExpression.java | 1 + .../expression/PostOperatorExpression.java | 5 + .../expression/PreOperatorExpression.java | 5 + .../expression/StringConstantExpression.java | 3 + .../SuperConstructorInvocationExpression.java | 4 + .../expression/SuperExpression.java | 3 + .../expression/TernaryOperatorExpression.java | 5 + .../javasyntax/expression/ThisExpression.java | 3 + .../AbstractNopStatementVisitor.java | 1 + .../javasyntax/statement/AssertStatement.java | 1 + .../javasyntax/statement/BaseStatement.java | 44 ++ .../javasyntax/statement/BreakStatement.java | 3 + .../statement/ContinueStatement.java | 3 + .../statement/DoWhileStatement.java | 2 + .../statement/ExpressionStatement.java | 4 + .../statement/ForEachStatement.java | 2 + .../javasyntax/statement/ForStatement.java | 4 + .../javasyntax/statement/IfElseStatement.java | 4 + .../javasyntax/statement/IfStatement.java | 5 + .../javasyntax/statement/LabelStatement.java | 3 + .../statement/LambdaExpressionStatement.java | 4 + .../LocalVariableDeclarationStatement.java | 3 + .../javasyntax/statement/NoStatement.java | 24 + .../statement/ReturnExpressionStatement.java | 5 + .../javasyntax/statement/ReturnStatement.java | 3 + .../statement/StatementVisitor.java | 1 + .../javasyntax/statement/Statements.java | 4 +- .../javasyntax/statement/SwitchStatement.java | 12 + .../statement/SynchronizedStatement.java | 2 + .../javasyntax/statement/ThrowStatement.java | 4 + .../javasyntax/statement/TryStatement.java | 12 +- .../javasyntax/statement/WhileStatement.java | 5 + .../v1/model/javasyntax/type/BaseType.java | 12 +- .../javasyntax/type/BaseTypeArgument.java | 10 + .../v1/model/javasyntax/type/GenericType.java | 11 +- .../javasyntax/type/InnerObjectType.java | 31 +- .../v1/model/javasyntax/type/ObjectType.java | 8 +- .../model/javasyntax/type/PrimitiveType.java | 7 +- .../core/v1/model/javasyntax/type/Type.java | 12 - .../core/v1/model/javasyntax/type/Types.java | 3 + .../type/WildcardExtendsTypeArgument.java | 18 +- .../type/WildcardSuperTypeArgument.java | 18 +- .../javasyntax/type/WildcardTypeArgument.java | 9 +- .../statement/ClassFileForStatement.java | 3 + .../ClassFileMonitorEnterStatement.java | 4 + .../ClassFileMonitorExitStatement.java | 4 + .../localvariable/AbstractLocalVariable.java | 2 + .../model/localvariable/Frame.java | 140 ++--- .../localvariable/ObjectLocalVariable.java | 18 +- .../localvariable/PrimitiveLocalVariable.java | 11 +- .../util/ByteCodeParser.java | 587 ++++++++---------- .../util/LocalVariableMaker.java | 16 +- .../util/LoopStatementMaker.java | 278 +++------ .../util/NewArrayMaker.java | 97 +-- .../util/StatementMaker.java | 180 +++--- .../util/StringConcatenationUtil.java | 8 +- .../util/SwitchStatementMaker.java | 254 +++----- .../util/SynchronizedStatementMaker.java | 51 +- .../util/TryWithResourcesStatementMaker.java | 101 ++- .../classfiletojavasyntax/util/TypeMaker.java | 2 +- .../TypeParametersToTypeArgumentsBinder.java | 58 +- .../visitor/AddCastExpressionVisitor.java | 43 +- .../visitor/CreateInstructionsVisitor.java | 4 +- .../visitor/InitEnumVisitor.java | 7 +- .../visitor/InitInnerClassVisitor.java | 49 +- .../visitor/InitInstanceFieldVisitor.java | 72 +-- .../visitor/InitStaticFieldVisitor.java | 52 +- ...MergeTryWithResourcesStatementVisitor.java | 3 +- ...pulateBindingsWithTypeArgumentVisitor.java | 20 +- ...RemoveBinaryOpReturnStatementsVisitor.java | 50 +- .../RemoveDefaultConstructorVisitor.java | 28 +- .../RemoveFinallyStatementsVisitor.java | 24 +- .../SearchUndeclaredLocalVariableVisitor.java | 2 +- .../visitor/UpdateBridgeMethodVisitor.java | 118 ++-- .../UpdateIntegerConstantTypeVisitor.java | 42 +- .../visitor/ExpressionVisitor.java | 34 +- .../visitor/StatementVisitor.java | 54 +- 110 files changed, 1505 insertions(+), 1477 deletions(-) create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/expression/NoExpression.java create mode 100644 src/main/java/org/jd/core/v1/model/javasyntax/statement/NoStatement.java diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java index 7b770596..b25986b6 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/AbstractJavaSyntaxVisitor.java @@ -268,7 +268,7 @@ public void visit(InstanceOfExpression expression) { @Override public void visit(LambdaFormalParametersExpression expression) { - safeAccept(expression.getParameters()); + safeAccept(expression.getFormalParameters()); expression.getStatements().accept(this); } @@ -332,6 +332,9 @@ public void visit(NewInitializedArray expression) { safeAccept(expression.getArrayInitializer()); } + @Override + public void visit(NoExpression expression) {} + @Override public void visit(NullExpression expression) { BaseType type = expression.getType(); @@ -525,6 +528,9 @@ public void visit(LocalVariableDeclarationStatement statement) { visit((LocalVariableDeclaration) statement); } + @Override + public void visit(NoStatement statement) {} + @Override public void visit(ReturnExpressionStatement statement) { statement.getExpression().accept(this); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java index 57034eff..fdcd41ec 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/BaseMemberDeclaration.java @@ -10,4 +10,5 @@ import org.jd.core.v1.util.Base; public interface BaseMemberDeclaration extends Declaration, Base { + default boolean isClassDeclaration() { return false; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java index 0070ab3b..efa944f2 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ClassDeclaration.java @@ -28,6 +28,9 @@ public ObjectType getSuperType() { return superType; } + @Override + public boolean isClassDeclaration() { return true; } + @Override public void accept(DeclarationVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java index 6306b19d..da76d58c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/ExpressionVariableInitializer.java @@ -16,6 +16,7 @@ public ExpressionVariableInitializer(Expression expression) { this.expression = expression; } + @Override public Expression getExpression() { return expression; } @@ -46,6 +47,9 @@ public int hashCode() { return 25107399 + (expression != null ? expression.hashCode() : 0); } + @Override + public boolean isExpressionVariableInitializer() { return true; } + @Override public void accept(DeclarationVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java index 380d4e2d..fe2d01d9 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/declaration/VariableInitializer.java @@ -7,6 +7,14 @@ package org.jd.core.v1.model.javasyntax.declaration; +import org.jd.core.v1.model.javasyntax.expression.Expression; + +import static org.jd.core.v1.model.javasyntax.expression.NoExpression.NO_EXPRESSION; + public interface VariableInitializer extends Declaration { int getLineNumber(); + + default boolean isExpressionVariableInitializer() { return false; } + + default Expression getExpression() { return NO_EXPRESSION; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java index a31530b9..71832c3c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/AbstractNopExpressionVisitor.java @@ -32,6 +32,7 @@ public abstract class AbstractNopExpressionVisitor implements ExpressionVisitor @Override public void visit(NewArray expression) {} @Override public void visit(NewExpression expression) {} @Override public void visit(NewInitializedArray expression) {} + @Override public void visit(NoExpression expression) {} @Override public void visit(NullExpression expression) {} @Override public void visit(ObjectTypeReferenceExpression expression) {} @Override public void visit(ParenthesesExpression expression) {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java index 1ac38159..076e613f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ArrayExpression.java @@ -27,6 +27,7 @@ public ArrayExpression(int lineNumber, Expression expression, Expression index) this.index = index; } + @Override public Expression getExpression() { return expression; } @@ -55,6 +56,9 @@ protected static Type createItemType(Expression expression) { return type.createType((dimension > 0) ? dimension-1 : 0); } + @Override + public boolean isArrayExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java index a6a6c89f..ddd0d714 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BaseExpression.java @@ -9,6 +9,53 @@ import org.jd.core.v1.util.Base; +import static org.jd.core.v1.model.javasyntax.expression.NoExpression.NO_EXPRESSION; + public interface BaseExpression extends Base { void accept(ExpressionVisitor visitor); + + default boolean isArrayExpression() { return false; } + default boolean isBinaryOperatorExpression() { return false; } + default boolean isBooleanExpression() { return false; } + default boolean isCastExpression() { return false; } + default boolean isConstructorInvocationExpression() { return false; } + default boolean isDoubleConstantExpression() { return false; } + default boolean isFieldReferenceExpression() { return false; } + default boolean isFloatConstantExpression() { return false; } + default boolean isIntegerConstantExpression() { return false; } + default boolean isLengthExpression() { return false; } + default boolean isLocalVariableReferenceExpression() { return false; } + default boolean isLongConstantExpression() { return false; } + default boolean isMethodInvocationExpression() { return false; } + default boolean isNewArray() { return false; } + default boolean isNewExpression() { return false; } + default boolean isNewInitializedArray() { return false; } + default boolean isNullExpression() { return false; } + default boolean isObjectTypeReferenceExpression() { return false; } + default boolean isPostOperatorExpression() { return false; } + default boolean isPreOperatorExpression() { return false; } + default boolean isStringConstantExpression() { return false; } + default boolean isSuperConstructorInvocationExpression() { return false; } + default boolean isSuperExpression() { return false; } + default boolean isTernaryOperatorExpression() { return false; } + default boolean isThisExpression() { return false; } + + default BaseExpression getDimensionExpressionList() { return NO_EXPRESSION; } + default BaseExpression getParameters() { return NO_EXPRESSION; } + + default Expression getCondition() { return NO_EXPRESSION; } + default Expression getExpression() { return NO_EXPRESSION; } + default Expression getExpressionTrue() { return NO_EXPRESSION; } + default Expression getExpressionFalse() { return NO_EXPRESSION; } + default Expression getIndex() { return NO_EXPRESSION; } + default Expression getLeftExpression() { return NO_EXPRESSION; } + default Expression getRightExpression() { return NO_EXPRESSION; } + + default String getDescriptor() { return ""; } + default double getDoubleValue() { return 0D; } + default float getFloatValue() { return 0F; } + default int getIntegerValue() { return 0; } + default long getLongValue() { return 0L; } + default String getName() { return ""; } + default String getOperator() { return ""; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java index 816cfe3a..cd55570b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BinaryOperatorExpression.java @@ -23,6 +23,7 @@ public BinaryOperatorExpression(int lineNumber, Type type, Expression leftExpres this.priority = priority; } + @Override public Expression getLeftExpression() { return leftExpression; } @@ -31,11 +32,7 @@ public void setLeftExpression(Expression leftExpression) { this.leftExpression = leftExpression; } - @SuppressWarnings("unchecked") - public T getGenericLeftExpression() { - return (T) leftExpression; - } - + @Override public String getOperator() { return operator; } @@ -44,6 +41,7 @@ public void setOperator(String operator) { this.operator = operator; } + @Override public Expression getRightExpression() { return rightExpression; } @@ -52,11 +50,6 @@ public void setRightExpression(Expression rightExpression) { this.rightExpression = rightExpression; } - @SuppressWarnings("unchecked") - public T getGenericRightExpression() { - return (T) rightExpression; - } - public int getPriority() { return priority; } @@ -65,6 +58,9 @@ public void setPriority(int priority) { this.priority = priority; } + @Override + public boolean isBinaryOperatorExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java index ad5812f4..1b0afcd8 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/BooleanExpression.java @@ -38,6 +38,9 @@ public boolean isFalse() { return !value; } + @Override + public boolean isBooleanExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java index e450bec7..1b91983d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/CastExpression.java @@ -31,6 +31,7 @@ public CastExpression(int lineNumber, Type type, Expression expression, boolean this.explicit = explicit; } + @Override public Expression getExpression() { return expression; } @@ -52,6 +53,9 @@ public int getPriority() { return 3; } + @Override + public boolean isCastExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java index 46fb65e5..bc90d82d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorInvocationExpression.java @@ -23,6 +23,7 @@ public ConstructorInvocationExpression(int lineNumber, ObjectType type, String d this.parameters = parameters; } + @Override public BaseExpression getParameters() { return parameters; } @@ -36,6 +37,9 @@ public int getPriority() { return 1; } + @Override + public boolean isConstructorInvocationExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java index 8ef90fc4..c526d477 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ConstructorReferenceExpression.java @@ -30,6 +30,7 @@ public ObjectType getObjectType() { return objectType; } + @Override public String getDescriptor() { return descriptor; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java index aaa23b7e..beeff52b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/DoubleConstantExpression.java @@ -22,10 +22,14 @@ public DoubleConstantExpression(int lineNumber, double value) { this.value = value; } - public double getValue() { + @Override + public double getDoubleValue() { return value; } + @Override + public boolean isDoubleConstantExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java index f556ad2d..9640d868 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/EnumConstantReferenceExpression.java @@ -35,6 +35,7 @@ public ObjectType getObjectType() { return type; } + @Override public String getName() { return name; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java index 88a60a82..0b5c90ca 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ExpressionVisitor.java @@ -32,6 +32,7 @@ public interface ExpressionVisitor { void visit(NewArray expression); void visit(NewExpression expression); void visit(NewInitializedArray expression); + void visit(NoExpression expression); void visit(NullExpression expression); void visit(ObjectTypeReferenceExpression expression); void visit(ParenthesesExpression expression); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java index 5673b187..ce3f7862 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FieldReferenceExpression.java @@ -31,6 +31,7 @@ public FieldReferenceExpression(int lineNumber, Type type, Expression expression this.descriptor = descriptor; } + @Override public Expression getExpression() { return expression; } @@ -43,6 +44,7 @@ public String getInternalTypeName() { return internalTypeName; } + @Override public String getName() { return name; } @@ -51,10 +53,14 @@ public void setName(String name) { this.name = name; } + @Override public String getDescriptor() { return descriptor; } + @Override + public boolean isFieldReferenceExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java index a0203933..ecdf6840 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/FloatConstantExpression.java @@ -22,10 +22,13 @@ public FloatConstantExpression(int lineNumber, float value) { this.value = value; } - public float getValue() { + public float getFloatValue() { return value; } + @Override + public boolean isFloatConstantExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java index 1c34d42f..0e389154 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/InstanceOfExpression.java @@ -26,6 +26,7 @@ public InstanceOfExpression(int lineNumber, Expression expression, Type instance this.instanceOfType = instanceOfType; } + @Override public Expression getExpression() { return expression; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java index 7175cba0..53c0b6fa 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/IntegerConstantExpression.java @@ -11,8 +11,6 @@ import org.jd.core.v1.model.javasyntax.type.Type; import org.jd.core.v1.service.converter.classfiletojavasyntax.util.PrimitiveTypeUtil; -import static org.jd.core.v1.model.javasyntax.type.PrimitiveType.*; - public class IntegerConstantExpression extends AbstractLineNumberTypeExpression { protected int value; @@ -20,16 +18,17 @@ public class IntegerConstantExpression extends AbstractLineNumberTypeExpression public IntegerConstantExpression(Type type, int value) { super(type); this.value = value; - assert type.isPrimitive(); + assert type.isPrimitiveType(); } public IntegerConstantExpression(int lineNumber, Type type, int value) { super(lineNumber, type); this.value = value; - assert type.isPrimitive(); + assert type.isPrimitiveType(); } - public int getValue() { + @Override + public int getIntegerValue() { return value; } @@ -40,14 +39,17 @@ public void setType(Type type) { } protected boolean checkType(Type type) { - if (type.isPrimitive()) { + if (type.isPrimitiveType()) { PrimitiveType valueType = PrimitiveTypeUtil.getPrimitiveTypeFromValue(value); return (((PrimitiveType)type).getFlags() & valueType.getFlags()) != 0; } return false; } - + + @Override + public boolean isIntegerConstantExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java index 4e0011ca..e8be616b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaFormalParametersExpression.java @@ -12,24 +12,24 @@ import org.jd.core.v1.model.javasyntax.type.Type; public class LambdaFormalParametersExpression extends AbstractLambdaExpression { - protected BaseFormalParameter parameters; + protected BaseFormalParameter formalParameters; - public LambdaFormalParametersExpression(Type type, BaseFormalParameter parameters, BaseStatement statements) { + public LambdaFormalParametersExpression(Type type, BaseFormalParameter formalParameters, BaseStatement statements) { super(type, statements); - this.parameters = parameters; + this.formalParameters = formalParameters; } - public LambdaFormalParametersExpression(int lineNumber, Type type, BaseFormalParameter parameters, BaseStatement statements) { + public LambdaFormalParametersExpression(int lineNumber, Type type, BaseFormalParameter formalParameters, BaseStatement statements) { super(lineNumber, type, statements); - this.parameters = parameters; + this.formalParameters = formalParameters; } - public BaseFormalParameter getParameters() { - return parameters; + public BaseFormalParameter getFormalParameters() { + return formalParameters; } - public void setParameters(BaseFormalParameter parameters) { - this.parameters = parameters; + public void setParameters(BaseFormalParameter formalParameters) { + this.formalParameters = formalParameters; } @Override @@ -39,6 +39,6 @@ public void accept(ExpressionVisitor visitor) { @Override public String toString() { - return "LambdaFormalParametersExpression{" + parameters + " -> " + statements + "}"; + return "LambdaFormalParametersExpression{" + formalParameters + " -> " + statements + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java index 49673a66..f6014bb7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LambdaIdentifiersExpression.java @@ -14,26 +14,26 @@ public class LambdaIdentifiersExpression extends AbstractLambdaExpression { protected Type returnedType; - protected List parameters; + protected List parameterNames; - public LambdaIdentifiersExpression(Type type, Type returnedType, List parameters, BaseStatement statements) { + public LambdaIdentifiersExpression(Type type, Type returnedType, List parameterNames, BaseStatement statements) { super(type, statements); this.returnedType = returnedType; - this.parameters = parameters; + this.parameterNames = parameterNames; } - public LambdaIdentifiersExpression(int lineNumber, Type type, Type returnedType, List parameters, BaseStatement statements) { + public LambdaIdentifiersExpression(int lineNumber, Type type, Type returnedType, List parameterNames, BaseStatement statements) { super(lineNumber, type, statements); this.returnedType = returnedType; - this.parameters = parameters; + this.parameterNames = parameterNames; } public Type getReturnedType() { return returnedType; } - public List getParameters() { - return parameters; + public List getParameterNames() { + return parameterNames; } @Override @@ -43,6 +43,6 @@ public void accept(ExpressionVisitor visitor) { @Override public String toString() { - return "LambdaIdentifiersExpression{" + parameters + " -> " + statements + "}"; + return "LambdaIdentifiersExpression{" + parameterNames + " -> " + statements + "}"; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java index 2e4678f9..db572c5c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LengthExpression.java @@ -27,6 +27,7 @@ public Type getType() { return PrimitiveType.TYPE_INT; } + @Override public Expression getExpression() { return expression; } @@ -35,6 +36,9 @@ public void setExpression(Expression expression) { this.expression = expression; } + @Override + public boolean isLengthExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java index 62e926c4..35e895d7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LocalVariableReferenceExpression.java @@ -22,10 +22,14 @@ public LocalVariableReferenceExpression(int lineNumber, Type type, String name) this.name = name; } + @Override public String getName() { return name; } + @Override + public boolean isLocalVariableReferenceExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java index fbdd8578..7269cd85 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/LongConstantExpression.java @@ -22,10 +22,14 @@ public LongConstantExpression(int lineNumber, long value) { this.value = value; } - public long getValue() { + @Override + public long getLongValue() { return value; } + @Override + public boolean isLongConstantExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java index e425a672..e13527ec 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodInvocationExpression.java @@ -40,6 +40,7 @@ public void setNonWildcardTypeArguments(BaseTypeArgument nonWildcardTypeArgument this.nonWildcardTypeArguments = nonWildcardTypeArguments; } + @Override public BaseExpression getParameters() { return parameters; } @@ -53,6 +54,9 @@ public int getPriority() { return 1; } + @Override + public boolean isMethodInvocationExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java index 4b135e45..d6f8c8d4 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/MethodReferenceExpression.java @@ -31,6 +31,7 @@ public MethodReferenceExpression(int lineNumber, Type type, Expression expressio this.descriptor = descriptor; } + @Override public Expression getExpression() { return expression; } @@ -43,10 +44,12 @@ public String getInternalTypeName() { return internalTypeName; } + @Override public String getName() { return name; } + @Override public String getDescriptor() { return descriptor; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java index 61be5dff..eec6108f 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewArray.java @@ -17,6 +17,7 @@ public NewArray(int lineNumber, Type type, BaseExpression dimensionExpressionLis this.dimensionExpressionList = dimensionExpressionList; } + @Override public BaseExpression getDimensionExpressionList() { return dimensionExpressionList; } @@ -30,6 +31,9 @@ public int getPriority() { return 0; } + @Override + public boolean isNewArray() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java index 8f11341f..b6591416 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewExpression.java @@ -52,10 +52,12 @@ public int getPriority() { return 0; } + @Override public String getDescriptor() { return descriptor; } + @Override public BaseExpression getParameters() { return parameters; } @@ -68,6 +70,9 @@ public BodyDeclaration getBodyDeclaration() { return bodyDeclaration; } + @Override + public boolean isNewExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java index fdc695a9..41168c55 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NewInitializedArray.java @@ -32,6 +32,9 @@ public int getPriority() { return 0; } + @Override + public boolean isNewInitializedArray() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NoExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NoExpression.java new file mode 100644 index 00000000..6499f7a3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NoExpression.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.expression; + +import org.jd.core.v1.model.javasyntax.type.PrimitiveType; + +public class NoExpression extends AbstractLineNumberTypeExpression { + public static final NoExpression NO_EXPRESSION = new NoExpression(); + + protected NoExpression() { + super(PrimitiveType.TYPE_VOID); + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "NoExpression"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java index 4c818bd6..80cdbb6c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/NullExpression.java @@ -18,6 +18,9 @@ public NullExpression(int lineNumber, Type type) { super(lineNumber, type); } + @Override + public boolean isNullExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java index 247fa0b5..39a47ff8 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ObjectTypeReferenceExpression.java @@ -64,6 +64,9 @@ public int getPriority() { return 0; } + @Override + public boolean isObjectTypeReferenceExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java index 02411ce4..f6b1aeed 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ParenthesesExpression.java @@ -22,6 +22,7 @@ public Type getType() { return expression.getType(); } + @Override public Expression getExpression() { return expression; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java index 1b3e1083..3edc0d31 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PostOperatorExpression.java @@ -24,10 +24,12 @@ public PostOperatorExpression(int lineNumber, Expression expression, String oper this.expression = expression; } + @Override public String getOperator() { return operator; } + @Override public Expression getExpression() { return expression; } @@ -46,6 +48,9 @@ public int getPriority() { return 1; } + @Override + public boolean isPostOperatorExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java index 530cac20..d7afc95a 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/PreOperatorExpression.java @@ -24,10 +24,12 @@ public PreOperatorExpression(int lineNumber, String operator, Expression express this.expression = expression; } + @Override public String getOperator() { return operator; } + @Override public Expression getExpression() { return expression; } @@ -46,6 +48,9 @@ public int getPriority() { return 2; } + @Override + public boolean isPreOperatorExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java index 93156fd3..abf5da76 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java @@ -33,6 +33,9 @@ public Type getType() { return ObjectType.TYPE_STRING; } + @Override + public boolean isStringConstantExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java index acca3bde..f22c6a90 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperConstructorInvocationExpression.java @@ -23,6 +23,7 @@ public SuperConstructorInvocationExpression(int lineNumber, ObjectType type, Str this.parameters = parameters; } + @Override public BaseExpression getParameters() { return parameters; } @@ -36,6 +37,9 @@ public int getPriority() { return 1; } + @Override + public boolean isSuperConstructorInvocationExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java index 10788db1..5ffdab1b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/SuperExpression.java @@ -26,6 +26,9 @@ public Type getType() { return type; } + @Override + public boolean isSuperExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java index cf774e39..6b1d9333 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/TernaryOperatorExpression.java @@ -36,6 +36,7 @@ public void setCondition(Expression condition) { this.condition = condition; } + @Override public Expression getExpressionTrue() { return expressionTrue; } @@ -44,6 +45,7 @@ public void setExpressionTrue(Expression expressionTrue) { this.expressionTrue = expressionTrue; } + @Override public Expression getExpressionFalse() { return expressionFalse; } @@ -57,6 +59,9 @@ public int getPriority() { return 15; } + @Override + public boolean isTernaryOperatorExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java index eb626b15..7ecbf3c5 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/ThisExpression.java @@ -37,6 +37,9 @@ public void setExplicit(boolean explicit) { this.explicit = explicit; } + @Override + public boolean isThisExpression() { return true; } + @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java index 8a467142..6d49d743 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AbstractNopStatementVisitor.java @@ -22,6 +22,7 @@ public abstract class AbstractNopStatementVisitor implements StatementVisitor { @Override public void visit(LabelStatement statement) {} @Override public void visit(LambdaExpressionStatement statement) {} @Override public void visit(LocalVariableDeclarationStatement statement) {} + @Override public void visit(NoStatement statement) {} @Override public void visit(ReturnExpressionStatement statement) {} @Override public void visit(ReturnStatement statement) {} @Override public void visit(Statements statement) {} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java index 825988fa..01d898ad 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/AssertStatement.java @@ -18,6 +18,7 @@ public AssertStatement(Expression condition, Expression message) { this.message = message; } + @Override public Expression getCondition() { return condition; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java index 2e0071a8..7c514446 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BaseStatement.java @@ -7,8 +7,52 @@ package org.jd.core.v1.model.javasyntax.statement; +import org.jd.core.v1.model.javasyntax.expression.BaseExpression; +import org.jd.core.v1.model.javasyntax.expression.Expression; import org.jd.core.v1.util.Base; +import org.jd.core.v1.util.DefaultList; + +import static org.jd.core.v1.model.javasyntax.expression.Expression.UNKNOWN_LINE_NUMBER; +import static org.jd.core.v1.model.javasyntax.expression.NoExpression.NO_EXPRESSION; +import static org.jd.core.v1.model.javasyntax.statement.NoStatement.NO_STATEMENT; public interface BaseStatement extends Base { void accept(StatementVisitor visitor); + + default boolean isBreakStatement() { return false; } + default boolean isContinueStatement() { return false; } + default boolean isExpressionStatement() { return false; } + default boolean isForStatement() { return false; } + default boolean isIfStatement() { return false; } + default boolean isIfElseStatement() { return false; } + default boolean isLabelStatement() { return false; } + default boolean isLambdaExpressionStatement() { return false; } + default boolean isLocalVariableDeclarationStatement() { return false; } + default boolean isMonitorEnterStatement() { return false; } + default boolean isMonitorExitStatement() { return false; } + default boolean isReturnStatement() { return false; } + default boolean isReturnExpressionStatement() { return false; } + default boolean isStatements() { return false; } + default boolean isSwitchStatement() { return false; } + default boolean isSwitchStatementLabelBlock() { return false; } + default boolean isSwitchStatementMultiLabelsBlock() { return false; } + default boolean isThrowStatement() { return false; } + default boolean isTryStatement() { return false; } + default boolean isWhileStatement() { return false; } + + default Expression getCondition() { return NO_EXPRESSION; } + default Expression getExpression() { return NO_EXPRESSION; } + default Expression getMonitor() { return NO_EXPRESSION; } + + default BaseStatement getElseStatements() { return NO_STATEMENT; } + default BaseStatement getFinallyStatements() { return NO_STATEMENT; } + default BaseStatement getStatements() { return NO_STATEMENT; } + default BaseStatement getTryStatements() { return NO_STATEMENT; } + + default BaseExpression getInit() { return NO_EXPRESSION; } + default BaseExpression getUpdate() { return NO_EXPRESSION; } + + default DefaultList getCatchClauses() { return DefaultList.emptyList(); } + + default int getLineNumber() { return UNKNOWN_LINE_NUMBER; } } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java index 64b1a0ac..d7b3d79d 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/BreakStatement.java @@ -26,6 +26,9 @@ public String getLabel() { return label; } + @Override + public boolean isBreakStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java index b681ef15..17554025 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ContinueStatement.java @@ -26,6 +26,9 @@ public String getLabel() { return label; } + @Override + public boolean isContinueStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java index e47ec033..b8d46ef7 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/DoWhileStatement.java @@ -18,6 +18,7 @@ public DoWhileStatement(Expression condition, BaseStatement statements) { this.statements = statements; } + @Override public Expression getCondition() { return condition; } @@ -26,6 +27,7 @@ public void setCondition(Expression condition) { this.condition = condition; } + @Override public BaseStatement getStatements() { return statements; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java index 8e55dcd0..1d411ffc 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ExpressionStatement.java @@ -16,6 +16,7 @@ public ExpressionStatement(Expression expression) { this.expression = expression; } + @Override public Expression getExpression() { return expression; } @@ -24,6 +25,9 @@ public void setExpression(Expression expression) { this.expression = expression; } + @Override + public boolean isExpressionStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java index 63bc28db..7218eee1 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForEachStatement.java @@ -31,6 +31,7 @@ public String getName() { return name; } + @Override public Expression getExpression() { return expression; } @@ -39,6 +40,7 @@ public void setExpression(Expression expression) { this.expression = expression; } + @Override public BaseStatement getStatements() { return statements; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java index ede847f9..6e3dcc91 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ForStatement.java @@ -40,6 +40,7 @@ public void setDeclaration(LocalVariableDeclaration declaration) { this.declaration = declaration; } + @Override public BaseExpression getInit() { return init; } @@ -48,6 +49,7 @@ public void setInit(BaseExpression init) { this.init = init; } + @Override public Expression getCondition() { return condition; } @@ -56,6 +58,7 @@ public void setCondition(Expression condition) { this.condition = condition; } + @Override public BaseExpression getUpdate() { return update; } @@ -64,6 +67,7 @@ public void setUpdate(BaseExpression update) { this.update = update; } + @Override public BaseStatement getStatements() { return statements; } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java index 405273f0..9246771e 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfElseStatement.java @@ -17,10 +17,14 @@ public IfElseStatement(Expression condition, BaseStatement statement, BaseStatem this.elseStatements = elseStatements; } + @Override public BaseStatement getElseStatements() { return elseStatements; } + @Override + public boolean isIfElseStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java index 1beb3f9f..692d4751 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/IfStatement.java @@ -18,6 +18,7 @@ public IfStatement(Expression condition, BaseStatement statements) { this.statements = statements; } + @Override public Expression getCondition() { return condition; } @@ -26,10 +27,14 @@ public void setCondition(Expression condition) { this.condition = condition; } + @Override public BaseStatement getStatements() { return statements; } + @Override + public boolean isIfStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java index 80ae048d..b41ea1fa 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LabelStatement.java @@ -24,6 +24,9 @@ public Statement getStatement() { return statement; } + @Override + public boolean isLabelStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java index ec1c382c..2e0d6a56 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LambdaExpressionStatement.java @@ -16,6 +16,7 @@ public LambdaExpressionStatement(Expression expression) { this.expression = expression; } + @Override public Expression getExpression() { return expression; } @@ -24,6 +25,9 @@ public void setExpression(Expression expression) { this.expression = expression; } + @Override + public boolean isLambdaExpressionStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java index 6989ccab..2a591294 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/LocalVariableDeclarationStatement.java @@ -17,6 +17,9 @@ public LocalVariableDeclarationStatement(Type type, BaseLocalVariableDeclarator super(type, localVariableDeclarators); } + @Override + public boolean isLocalVariableDeclarationStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/NoStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/NoStatement.java new file mode 100644 index 00000000..832269a3 --- /dev/null +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/NoStatement.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.model.javasyntax.statement; + +public class NoStatement implements Statement { + public static final NoStatement NO_STATEMENT = new NoStatement(); + + protected NoStatement() {} + + @Override + public void accept(StatementVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "NoStatement"; + } +} diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java index 31251c79..3086222b 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnExpressionStatement.java @@ -23,6 +23,7 @@ public ReturnExpressionStatement(int lineNumber, Expression expression) { assert expression != null; } + @Override public int getLineNumber() { return lineNumber; } @@ -31,6 +32,7 @@ public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } + @Override public Expression getExpression() { return expression; } @@ -45,6 +47,9 @@ public T getGenericExpression() { return (T)expression; } + @Override + public boolean isReturnExpressionStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java index 0a65d1ea..efb8d9de 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/ReturnStatement.java @@ -12,6 +12,9 @@ public class ReturnStatement implements Statement { protected ReturnStatement() {} + @Override + public boolean isReturnStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java index 2be4ee3d..bb56c89a 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/StatementVisitor.java @@ -22,6 +22,7 @@ public interface StatementVisitor { void visit(LabelStatement statement); void visit(LambdaExpressionStatement statement); void visit(LocalVariableDeclarationStatement statement); + void visit(NoStatement statement); void visit(ReturnExpressionStatement statement); void visit(ReturnStatement statement); void visit(Statements statement); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java index 6b4850c2..5409055c 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/Statements.java @@ -12,7 +12,6 @@ import java.util.List; public class Statements extends DefaultList implements BaseStatement { - public Statements() {} public Statements(int capacity) { @@ -30,6 +29,9 @@ public Statements(Statement statement, Statement... statements) { assert (statements != null) && (statements.length > 0) : "Uses 'Statement' implementation instead"; } + @Override + public boolean isStatements() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java b/src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java index cb1105c7..83e8f295 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/statement/SwitchStatement.java @@ -22,6 +22,7 @@ public SwitchStatement(Expression condition, List blocks) { this.blocks = blocks; } + @Override public Expression getCondition() { return condition; } @@ -34,6 +35,9 @@ public List getBlocks() { return blocks; } + @Override + public boolean isSwitchStatement() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); @@ -63,6 +67,7 @@ public ExpressionLabel(Expression expression) { this.expression = expression; } + @Override public Expression getExpression() { return expression; } @@ -90,6 +95,7 @@ protected Block(BaseStatement statements) { this.statements = statements; } + @Override public BaseStatement getStatements() { return statements; } @@ -107,6 +113,9 @@ public Label getLabel() { return label; } + @Override + public boolean isSwitchStatementLabelBlock() { return true; } + @Override public void accept(StatementVisitor visitor) { visitor.visit(this); @@ -130,6 +139,9 @@ public List
izQycD<<50V$c*N*^@OdG*H91fYg5#Pj5}j& zV7is}$~1lx6J@XbHk!}=4&gBVTn%)}*tpQvISkpoe!jph2$(V=}62#;K-r z=px{4V=SM&*G=uJvW$W==2-~S-Tw&1LunP`!S#K40}R=1o4hY>&d8@W=iojNb`+A|?nq)n}Z!cpU>tUAAOR^O1p%&9v1;e~Mr!?1a_tMZAv zG7he;E(v{J#iFLmvATrZjIn8ek0^#1?>b^l^(ZZA24gorKzagWWvhaQugIcXO zdv?~F|8oVpSVr!Xo4HtnUjoMP&&f$19Fl4>gF~eTLGJ2hhg3}_o3#}G#U%!zn?!RP z!4{mw&)JT{?CF+aW0C;KK6@%fbNaE0UTuSf7~|O{OjiOUk6cnbf^XVbX8_i%@uvg# zKEQS)2!|mjBsal+_k6f6_m5iZzOP2NzI$AB0?Y=2XTQH(tw;OXj&ZqkuFm=SKB1Ic z`judhBRFQ^Vxk)&K_F!Gdf#ou14?8X#gV$8aQC5b!&aX#wKA5qk{RwO!ly zj9#S3fpfT#SU6nAV|8c)SSQA-8;&=4hf|h4AmqgK#I6X|Bi^JQUvhn%9ZFX#PLyfS zQu$;$zM^i?+bX!Uuk9@9_E&+n1OxbcWwm-2^nejN=dF`W8^)>>#Cc$L@=1?vuQ#K} zJjXsYEEOT{m5D-P)P}ys7UNH36m!HX{b7{zuY4R~4pfGV5Vi^- z?R147D%l%2-?es1+bV6G4n$6GRV^?5ko#`rA+~(xQE|GL`XUzQacBzeAN=zkHQF&6 z=utZ0$Wf?>HaxHaz7Vdtqw>KzA8y(;k}a|po=YGKccCDE^dDZ0NeGE>hyCRQSXcu* zjL_YUN!=4suPJ1@J6XnmB6T|AChiP{Y{!9n6(*xTCBh?gJ`=4!L#e({8F5LQ^NHK@ ziL&LBgD@%`@R`-CxQ8~aQh5hAwL^!2&`ZWw-(Z4`t~Sf4PcwYnqZbg3OF+Q)geEkt@yolEpC*~;%L4b=P0^y0Dri{E zl=}4S$X4s4+!}Hx*_v{nC%i({C)#4{GV~O3b$(7WKQgmbWK*gp&bxUUMh%oA%7c;! zx(&fgJb*6c%(FyzY$UeZKe>rJnXJ6N!JD1G?UfS-rRUrJPT&TM*qJ(ZaX>5z8WWQ`6I%l)iK;Aw#p*5+1Sy!PYF$v#d(F~e zlJVw4(QrzR8sIQTuC8dICuw?1O_$+skzN@fn3j6>>((^zdtd`qFYxpb#MsTs)|B4a z%*4#f(e-a%f?bi>euxQf>m`*Wh>X{X&2mDcV0@v-Mp(6_xIYO_n&b6-LtaF|W2_tO zZA9^^Dc1Ci7wWD=a55)8vNT%E`L&C86`b5`mbh@Gr4j_ zJ65U{1#E6h7CTW#*-{BOTl{*N7;L~W$q};8OAJ@KZk2m~CDWGEh{Nnixn=5U$a^A= zO6S!vB4PRte9wb~B{5?86_fMf1@v*wmE5ub4AJ5}vlh(B=O394d`*aR(u1JTT8v9r zL3rHzzfocS`UikN`u_mIfnx9PO3%dB>c26v|9U)O{2`4G2$4|*LS&f#^KoJ0ztYbp zuA&Zhc0k;goRz&95EbVRskd*QXR>sT$RK2|atttr;E?nmr)Gj75#sc3S% zg{HQMpgQRV8-`_my7Aa2dgk3ABO8PM>4BZE%xJx*DXG{s)S>6xfo)V)rc4IDjb7in z`Z(ts#~iDF@#K+*2i08|T5%Ljesv|JsXb_jvc~EXk*k1}SR{nW{^71p*sS^6?%T5T zV8311wA*T`81$QT2A9-60RnauX9iN(QV&JgCAnDW)U?=g28yZX9h1 z4vh|wH(>=d56jrEhB&k>6k}hs#G@_%vQk-e#j~}_c|~s$8l>GXu!-@Q5qW4bq?Vy7 zP9baCP`B5MFtnz^UeGm*exwy@SSJcJ)DF4Z4gKAUiXla+o&n)0)w7AvTpW}qSYv`& zqk?76l!rDUd?U?5-^216(?>K6+y4%a`Kv3kd^3wL19rhv;OpP=r+@X_zjZ++BWECO z`M)gC&=}#rnC;@9maRIl?nhk_HllM%XyD=lsKf3R^j4tKza1I)0>V*L^|~Ad?ga_W zx6eO3LC2B8p+v<(PHpYmcI|328ph=}W%RFXW+<)jH{D3DlYo0s5p2!#vwpyG3bA=e zX=7?d4IO&4$nyS)S1PhlgojS^OsZ=fKJl+a5o!I%gVMbs(vnXp=`(IHAB$6n9ncsb zNG$LC*VuRX-}IS2|29vlh(P040EgWZ(Cp>=&tdnUzg6DK#l_0rLecTBUAeHc1@JC{ ztJ%Lo52^Z!i-u@ppK}~twdbY;TmTj2*_F z+fm#PA_J)+(%V7A-EbD*%_SFH+0itLOKwFV^KP}}AAF~R5Oj3rL-k?hh-5bMKQR++!1!jkqtL^Suy4@riZoUe8XE7$ z+A@PJ=Ggr#^=c<&YFv@04~jUUH0sGHVz?)aA(1vhA^T+FCUbSFd||7OKF!UQ%W|L1 zlH|Rn)}a}Bdt4Pn1kx+m;01gyQ?5ATDuKH;efTP!i#%~jMH+JT1BZ6E1>04BN#&-a z^mlZ|EIqYo+&X#tsZRPZruJ%=FcPFOTQS$38cIz12< zafr+!DU!R3L|QFevX%8LK!)!7!nOhBhx8JsGci4>SQK#wg9Y|l-j8v9a|zKb--pe0 z9z}#+pcP>7@e3)(&HZUtOuf2*HNL10U-S_rOb3-W zA_>?co@&@>0BiVYGd18;U)yS!GB_x8g-A9K*PdgQWCz0*v*aSTM1Db~H3GlG)EE?B zV0{pydHh@2{IAj8QzOrk2pj>yz=enZe=`F9+4WU{)|9;kaC|r#0b!;8Rk0vfZB7vt zXi%AVnHkv?-W40R2I&+knNkx0(;Ov{(2dBbaFN?(mt}C;?h{vO&-MKi*Zm0W^j^VMae>N7F{0s;qZ_VIIQ_r$h z9*c@o4-2IKHEx(qoR%+WI6r9*FvhBs8vDM?SEsX$tK3S>qT^&UD1elw_C{3!5x!s{ zb)5^o;Pwcn$P?S-?L)$c+(95}yy`?(ZwtHA4%M#h)El;bBL--j&Z3teB!Dfi%j(6* zbMWfiPL+ZCPQRtR*y(d5l>@Vgp)h1iDho(_(dRh`TaJqI#VklRAVz){U4?}j+y2M`Cz>QTWQY@ShknOmmvx?1yyXUGYQ`F`W9!lr`sLpz}*LTSh>tk zu;`0abx;gWkzg*Re=^hHG-TDKQbUh101Z*ryRlq z#^aZ+M`Rsa@7rrYR~mmXb73y&tnRwYQ66z!YoCbs6az9N()WU8E1qWzN0(_;xo z2N_4Gv)^7HXss5i+d}`v13>Y(7sNySYaci579qrj5@O6fN8)SIAws85Ec`7NbpZfOv2}_eoGW zf6!~8zan8JrZV#P4>c!b_xLdIP+4wsaP@px_v{hUGDuf6tJ34C0145mj)@av;@q2% z-Qjea2NCfx9N-W&*P?+Y7$cHm-LqzKIBH7(hI%!MG${%`2E$Nj?4wxMbf`Z(ZNgmrq%lEI&U{$r`9UJq$r1&h=dm0$7>>A_|5#75}Pz>>kxzW z`hYb*5}F3b*U$a!nzz`!cqJ!naPbipM_$e0c7&kuyOOzj;Wew2i^@cw6|S1a0&t4$ z)!ThJdyCeY-@p%OaWMMY+ypV5J2YJx1#jcD=)NlOH+TH6RuROs{2T+q>cWBLWd2t( zkgPqhTFgJEp?@lnzb(Q5EgMg?BXqwXrpekAU}2#kfg0sm38pTHU!vz*h>J?XgmC3z zS~iS4$YB#}#Yo@Xc^TLm z;2G$ZDN17@nurV{W3TR3z(II0KZG*%X$3OwP06{o%kBRd-1H{%Q6K&8!yn^qW;^7| z(iiA(H_>hi4Ez}lUWeWCk8XVnygvBa^R6@)|NP8FC`fdGMUZl1g6-BY_zdk&>E%Tg zlYjSQgdM+YA@_C<^A7qX`%GT#r8Za(w91ugN^G=_18i`QBSMlx*3&}^?dq-0+!aM! z@Bqk`m(3T6E6BP)TFr{qpyg%b=qMZOwnfIP-;BF!H$}F8xKL-k@b1}E!z-VdK617s zhT*N+a5Gk9>9iBOX1Zfkhc7B57V*5w)(YKs4mUm7lIOHk-|$waTJ|HH$Q6Mhr(d=s z0nEnM_LCF??67ejuWupdaV?NfSH@0P6?;o9`hSl5Amn-%nc&-HcSU@i?#v_#J5Hi` zzkAKvVxd9()^fUAL6=*|$Kfs6{MsT4Jt+2ClaYqCWE=eSg=KgfMav`ENo{^C6U_owA?QYOko)Cc&$(R8bTXW8G>m{#{J^N$~iv2 zv((|Tgn2B`9DwggETjZqnGSE-Y-=svvUomSg>f&G9MG`Ubi{Y3T8oUQJ{4&X5{83j zW3X4{Np>fU{3ZO{4n8&m&7=9DQM z(t2Wu!ps^=4W{(B6*27Ca3Pqb=5xCq75J;64>!*&lC|!<5{1!Z3~)m?!_1l}47hko z4Bo>S^hd+^jSZY`WXp6wE?Y}<6)T*!^_jjf?meOWDcFs_2o~HEiM#%|Q@&y8{+RO= z9}w@MY49T+sY^+WIOq7i23FivwafkC3hqId8MnIZBylhVL9jso;Q*}U> z?%nQPeQ*bS$vCxY7iAl{;}Pu9IxvpBEe@}28NzX9>P#3^e#(mIp$wDJH?V8Jm&KB8 zX~T-X+!kxGV$p%|MgsprSIh0e7TxoE6-=)K9baKK=~YE}b-F?N7IxUY4qsmYZ*7=C zE)>56AToqK(JTJ6F%8aw6Z6Fkb?8TV{{T4`>F2FM6&P)cmYhdU*5fRP^*X=oN-8!8 zjHmNn>74;S4(x>0ukwdB&^X3FEl05s(fs{teQ{2hzqWeVAX(y!Ij~|{5?{mK3*Aj9 zDt-y1qHi@I#~?je9x++OVkG*|nT=E&-)xCOW^Y^A`HK3fIF0Y$zU-An*>(z83Y&f; zm}eX4AG25(Cr3VM#63Nd!;uGK4Os&eS+vu^K2eXL#!H_Hvg7vTkJeF!E%`Ii#A^r z%`Fy3RC0$*j!3O1UhF>f1F}5jq?W*=G2yPTtw-e7#-mb#;kIzTh+5!*>f?bbHZFO5 zpCC_cRCt3G!la|A*{N3z4nu5SD4QdK=5)c`$f#9~0-@wxJT!wt&PWytTw+0MIcxjc zI02HPFp6UG@A5|N9N~0NjNbhkk6^dH$7%T2TPwH(JJ7F=E`|q4+KLAp*3z<`z#u_| zxo@);B~xUoi7k_GsfmXQW?5Rk{+s2zKIOMxTUeOlSfUT1I)=> zID_!EpNj5I@9iaYgzpH{qKVXZe#eJ+P3R6Kx}h5-y))Zy@$KwqLcX34VqDP2 zg?z%Pz_X&vvbNUHul*ipv>Y86OQhP#aj-p*XmB5ui{l5gw>jumH9txZ0j-Ac?AoYJ zi{`aVaSdvET8HB%d!NNuocf91`U|`4wH^-lR(pfYy3?97H>=O&rfu9kB>!XyhUHZA z22vNL4O`=S4MjL@Gn*FIZueakWt)a-58v%*MugdRB#h3g&Y(>X;0!;<^^?~meuM}u zW|x1+Q*VXKKBds{y0gQ*vA`KlRJpVmBi;d)MqmFah={G?qtizhSIuoZseOyw&`3cRn3FoyWJZ&~K8Id5KHmp7G~%1IVgSgcnvPXn zLXJTAO)&VE;D@Vy8TU})q*RaqBR=qaAsXe=_uTQMmb&R2Vy7>+u)LCYlwAzOm$U8_ zDTcDaARxB8#*7)?2XROd+n-&!{;z&sNjV=X3<~Ji=abs?<#>>zFMh$t1Bdf=$Y=!j)Phr{Df>uHdf` za%j9vxd$8}_COu|S9Qt1iah=+SMWc3cIx&v|350aSA9waxR2-OpCB`05rRUx4UM3h zK!VyUB#9s?EmcR;32ic5B~v{(H4V#>OZj&5O-~9vo(9t|;B$9$bubo}v#X(pKNAL7 zgxqQGc>8MeDW}i(YUc3cy8RmD&`DPq?f`~|>8EgY4pZ{r;mANrkkz!96MK{mob&oY z9>EBn=sU83{l3K6 z?mZmw6%O1)s>M6Roc0!nvrV4O1|}zi&<>x3Kq! z#R~S|ltNO$F-z;SjOgTWzMN9(M<>P4{Onzwb56qw@0N!$H`U&m2q+(&v2 zeTpMWM&6Fu>9((dfpe^kbUVKaXYP7IgNZ8eEc|S9J1N1NCD*E5G0KE+VcV*}elv#I z;DFS5a=Xcu*_acn|K?1Pt-;HE+o7q2pIXi!gW9MJTSDi{;?zn`lX3Oo4$LSc zHh?v2SQh*jQA$RPYkO~oZzmd|j~}t4tzVWKX_>_c2N7Pi!V=Kn3)NLx#-EnR?~tX6 zeAya5T4;YV$n||Q`I^wu$RE;jK`^-SOmK+LlaN4?9VEy42btv!Jk(c$^DRi=5xx9W zt{TMhoWb;uj2`t1t+HH1k%bdO2al|Qsr24zt2YVBU>~sR)^E05Gp_gnkWAQw zrndO;Y|`CpH^WZIKA}mq0hhzlC|v z%QcaD$&x&~;hVK>Cw{HPtAN0yn%zKonqtx`hFnQlbRaE+iFDA}v}V z-l#6AmZ+zFyztih0o(IXdsK?pqB>YI?fN<_YVk_>D!Sn(sbRX_BwLmoIh(hf2XOHC z!GA~S|M`j=kbY~2$IC=+!V||K=Vr*eecBIa9{Nz`IZf^eb`QNZOn>VsJGu$I6-Hws zEFlm#dsZ2gz((9lT2kamH(D^}C`q*wJAhP0?zDo2C@Ud7>WyMreR!Itoi@+zC)rzl zOcQ5+SjJ|dB{G&`z@}bqY=iQ+@&mup9)6kbxC~F1GkS>9OGNq7*i4!=_t#f)f(@hw z9QGyWOp0tAH&SdT7UlU#FI|rTDXB1ks`k80TbgF*M2&U!l1#+8d0&%I?wS-QRF|c0 z>O##Goeb9&)J9WuXHhK%9DO?H!&XIWOG#F!6JUt~Fm8|X69`1iO-51q1roz7*}M!P zic64@h=kn=lSPHCsGydH!RD>ggW6x)V?ABb#_*WOV(n$s`s>5*i=I-Q>R1yt`##;- z#b6$$NlkrWysU_#uVY(3*gRc42L5#2y2cW*!BWnII;fo#VhB}Bz49uFt+6tF{$mHJ z5fwhkY`@N#GoPzMf{nc7+oBDNDkxW`Gv&P?F4LkIob5Nm)Jxwg zX4aHChHSE$OuGW3;?K?6c$bSdVIGZs z1S#HB27!sZ!sSO_Vm>f`vk}=bBxG#Wg;~Hd+&i)Hz<2v*tTv$etTVt#;=U72qaN<# zycd_|p{Fukv+w?GT8qb8YKzm1kdg~ZV5e5nYPxaU@9(>VcV4NIg3JtyJ8X*kH=9FM@Z zC+l3~VHjTBwf#oPQM?lFh^_r3c}esb&GJMh`9wFjR9ggv$?jQK_=Q`_5}Rowq&u7) zA@ETMjB!IdhVLUIrx_#Q>V&L@E{gsCyhd(sBp$dR8v9(8e4=&DM-v=3Wov~+9`Thj z>-304!_kK&?p|kp@MRunYdU5;N5Dujfp;t@;E~^%q@dTS&o~LzYf|SHq+4rnUxm!@ ze7S72NpOj#N_pEVP^Uca0a2$UUFr=>&P%q@gMi{rMo;y;I6?PV2II?d(*LbC<5SbL znu()P`0J@L&v~e4wj9bO2FGYIaXn(#x}Z&{K$I^J*6`{ERGJI0H1TS#fYAM%#myb8 zJU5YVFu1|$+Vo5RpvK_Ig-W}T!DNVT_0XlHd1~z$e}Da|&&)P!hJrKNW02|>%ml$4 z$8V(G*tXuf36{1ckUS#t0gchMVTP;k>*4xz^M3Be3D^WidG*N0+JE#%x%DW$jvW(! zh%iD-)_XyZI7Yjl=z->pK`^$e4j8zHSFsKlD72lHX3*?iki6))xewC1bGpPhEA)lq zd4)*5#lwqb!z^`g)<2aV`>nMT>O5!Kot-$}A0`zZ9%pXNU`*iOB+0(X;oJ#LWR9bj zh|JnAX5#ddzIl%N5w`dW5d_)ylvQacBS0%HeGNj@m#8696+oOFWBe4`h3xY}Hd*+Z1 zyBs&yFsCH{EdEiV7%K1#_F5d}!SMwd*2{;qCjx&8_VM;ZrTP<{$cCgM85eM(__MH@bcJ6=dm=#ccqr7-8Jw6o!Zdbfw_ zsnb4ExXMSWWHC1lLm***GtB`VO z%U5+KGz0yvOTH)u_!l>vbgao_Nh2zGl1}pPgA5nxp(Yk2n*3c5A*RgckNyKM(t*M2 zDW<-kfrw})65!9zP#rBCbR``Tiqs57+#^LZm~<{?bbcbIF(d0gMxsdvrTAhs8q?Bh z%irOx5hu+~ZH;DsCsNWO`B8`&J^q{3uj^@_kpdLMW61yGlKzhtH~pL8|1W=EbKM_T z6aA0G=Ju0zj_CQ=_SD~{|+2QwopFktb-d*Wl!xd5!dIwlDA z%(SgofEotJ8i*8waj2Z;L>*Ys-7s8CGNe#20;r^D44IPF8))(b24A(Y^JNRrB|tZC z^-%JGF^)OPThKnFv1pdQjNL{?^7*)QQy=a?dn_j(@t$vS2k5tc>Xtne3V!U7^?OZP ze)=FjqNC?dJ&8hyeVN1Ap0cMtvV48?1P&9=aUqxH>nrlb&Zb@~ZLY=Rxs}mpNjzGu zzZZ5}bO;jXS*kJNm+N%0LXu;@NdnBI*`tCP`o~kO(7#5f=}=h(-;?{^I4xIMhC;hI zDYL_JO_e&#G zXMsC$z2F9v*41^YEAUSnT}7%6|K&J`&BM>^6^P~P&PDt3L?QxQ&NLg!?j|<~UZXUb zjh>-)uHIf#jPe%p+QTOc$%dv7z1?tmP(r9SY`oV_croDG{{3q!I{VvcSZ7k5y5fiF z`f5w3G|1+X$bc|kaaz>|#Y3}RvFz0o#@Q;AKabGU)zPPaNOgy3t9gC7)e3mQ;_7gX zcI$DgNtfkK9L4j;pcO>;EeEtd<*yDM?cLBKLy)&@0mmEK9tT7!t`IPkEA3And+oC( zBCP?*8)a-w^qyc3GatR z;-d`X9c8;b8t6UYoM#Da3q=knShMX%;!?BH?XZ8XSZxfb6X+pv4QDCdLMAQpAhBALYJ-~;FpllJdO5l2^PS-G9si>ya4%QC5 z6zKLm3z-aPlpSRW5pOiDDgDJH6EN@*p@a28Z;0#GPyf6Ut%h^d{PlsD>_s4kcycI! zEr7}Nswb%%g4zSOuu~UmM<~QN#rOj9(2ZH4G1Pb;GU>xciA?TfwLyMRJ*Olg=| zqa|;c|BPjj?{mc=IV3%!dZxG&436d26AOQd+sE3Kibob7gr0=ixtc9e+?STg!ShKH z@d?rhQSk2~eWY}q4Rwi;?F-Fqc0nelz-Oiz?m+qssIx(cfm-0-IN-Xc}mg#q#!w}_a~e*h(CN?ROBur_UilBNT1if>@_!z{O!x0t|GVUo3+W@ zA14m`e{2K*Z@H7FqIle7r{Zbo=@zy4rt?E&zBz90IcN&b7Fp~Rd>G&sjbGzcqnZ{Z z@K{I(Rr9A8OSBTOPbL=SL?TYdZo#c!SCQ#jW}m_HONWIokbQ!9Nrde>|74HnpkJ`O zeihOBZ6(JAGngxhH^#FC)`x00{e-ngmh%R(=E-zHW~8_c@hHuAbaW=)2La{_zNxxO z3}{8L%AaUtCFqH=G<5?u!cesz43AV%MY+97V>sDGX?^d5R>mxHOEv;@aFH3SAK>xj z>S0f{=IONyoj3o{>I074z}?^-y(lC!&Qg@8n^WvWr~KZ3Xm;~7Q}#NVYk7+i<`Luj zXVSO&jTTg+K>0G|J|Rj>JW5su!(34YLF%>|%U-0T`;4ay9M=r6q9SRIHnGY&@*;u) zT=77~SP1|X!SALDC?ttQv)_6<3H>axZz}qr=sUs?;$y;0AOKOe9`GysT{DRk{q0Ok zUpD53D~CyF9l0Eu@`a>)dXi^%ciu%Q=Mw0#6Eq!snc?;5=NgMQ__;?Ve>?Zr-^sPr zgk3BRVR{jp)XMF858=b$A1B{W?V0(9h+pUcUUBXH_c?Ej&sUfGRK9D}W#HaFG~`74 zrbOe4NkqxNy4?EzccUv>nBCR~DC%H=qK@Z3jV>i;2WvAESKyl?FdJ!Q=JK~C{@((V zxk<8$gFK!Y}6IP!1b~{ZcLS=4!^{6hgwHPhVhk<(zNjikyGu; zY1l#`{y_k#UuUnq$~mhe%QOAML`Lj>ZTd713n@-V#jCA6y7qU!#Pp-~={kO`*lFhJZ2T$ts@(Gy zc?#+ZWE{$ETxc8~P58ISilbh^-zyP3R3zbifg2&l{xZw4kIfMp0ERGU#<@L|g^%D)sxqxwKkG3&+eJ?NY{LDKt*E`B?e0nN%2 zpNc%S2F=P8r-iO~@t~~y{cjN@7F*3W8K8Ly4zyq-{Y_$2X23E#X7(;t zu2$}5|8o|pRP~>MSXLjpUE{>IXYG-wG{)}IS7V}B8DkMLYmvpLFOWIr>vrzxz_N7y zyCdmY&xZeBXI}wS$Fg-zaCdiig1fr~2*EYz!QEYh6WpC3!3pl}1cF0wcL~8Ef&b*) zDfKAd-vL&my$Rq^mxzUAkjpVJ$6PLcSiYLE_W(yR-UkZ z;sXOyV3FFR@Z)cdM^JWbFweGLE%NgUGLq${cY{$J5ywaG8{T>E54f zqeQ;q1l1*gk~wiljg2Hgo3$pabzQY_J#ng%J!;JODW283IgWKLwBrIOy1OA&VFkC6 z6#uE|z}?W|Ff@mu%&&~TOFocwN<|R*Lz1o;f^l3Yb|7z4pKhZE?dU6GI1|f}n2{~1 zd{ORWjco10oI4Fr`qxNB)j7D4*y=m5cX#(i_~0X3A%LAM#HVPICbxO|9R@;D^>sHA zN*{918HIuz6(R{xp4Fn3wd*+HQZL++y|ie&Bg-8+Uo7H`wuvXS)-PIYlV^$PWJiNC zP38ipNokfbHbB#Y%w%r)vcmk*Ad9o7vbLBkXz9Y7*-|2Ed+sQLU^cEvp!+fmDi11E zHybDHU{@M7K!9^77l{e6+$lFhnm3#tfhcre?Gxjst&y4BKC!|&&&@WzFT!R{7K}7D zMHDmvRa(U~BQo#&O+?S=v%Axe{xlURe6PqA$hujX8gZ&rcT!MFF6$Jb>9*|R_~c!f z?BMEAhFfz}U2;=xP~H$lm(6$+D;7RL#8xL@F^>9$qiQVnwpNN^@@}5uONAPUeetJ{ ziq|Vipnm@Zt_vJRAny#@S@a88yvQ9kXO{ripswiaWA7|_`=XU!Ezqm{8Y~l35Rg8g zBo^hr7_Hx(g&J_K%G0&FbZ1;~abV;zAOU=&NP~v4AR@k>Sj3d$!I_|gf?cKLWBmr7 zC8vNWzRjJYy-+O4)$>v-DpM7g4pA&EJ29{-@mdnFJUO~p)>`ne@mO%T(AsOiOi6kF z43YA3W8;wDqoQ?Y{^0ba)@Aw2bt9S>Te!mZ1mdmF%@=V2qQRXC+^-Bt_wqysn>k86 zM|u-Qp&A?b8IEQ;JUE9lAG>u^X4o#x($o5RcJ`Dzg5+=bL^fi0Fizj{jqdpKJ>6v8 zWYydt%|QHwO%ye4#uqg?S20OWc(TE|bp?L&3_VPmN2fc^OPij|WY8om;@QP1FrI(X z%d@VJ)e)8{d=oWN)~VRw(k`WD>od$i80?KQYyj;VuaZEum_n_!GhtS@!=_U9sdfgY zLv7!gqvp^VyKc5!r2MdJj(ly4R0yU;i&)`VFRZLn({ljkStIW3zT-P4?LJ_(9V%6B z1wi7RX`vMNO98B1Pm+r0WpUh>>5>Po`B4Y#*3rkbD2?;|7Gfu|o{QA&v*w;f@@mi< zPTIt+7wciZ=b*SRw>Kz1&O&Bry1hB)xN)sk-?7iA|AfJl)-v5ck_+=?Jh!^HOu#yB z&^a>TS&vaEba0ue&Ok(ODfVQtO2(-k`66}{WVe-5%xig8^FA`g$a-eEa#q8cFx&UA z{r;z`@^on-G%LCpZPvV#4YJ(}-7z})9`?03ks9ND4LJ2|h{Ef=g((Mmw6@rYtQgZ! zhRh*#CKhk3%wau>tRl4(J=hBD0?lf0xdpK!d-0m zbpTUC(cydp!`L0(k&YJ38Sl(5<}pfe>)57d7+0#AoR8+WlGvDT)T~)uQdM+L_1@B& z*J?DEsHWMOV(1RA(HhV-m+}r8D&sn}euPO~?95p~L;h{EUleH=G50V$1 zVlZVn;A(N3cBvR^rWrU0Lnl4iyvu}vxJm;0HgzUqp3*WEfik3wf*#R> zlQgo)+Xvw_N*5am1J z8OCP_Ce~>XT3_H0~$ijnyU%D6Sjpj2~Bgmf@dKA=EqoG&>1y)x=jEK*7rD}S^DB}hQ zF=|0<%7!ooW4^G}szMs(7Fje;Bh1a21vL>*8NS+3ylGvu4rhsROT|r8i79UY&wdj$ zAe1gju+KGMWan*<%|^x=A7r12TAu|7@l#h$DXK+ud&isIb31v|!?p-`xm2n3KGo8wS zYrS)AU6?{20&2~(k&p&e8X}etS5Jb%hl~tmGhE2yx)-MkM|YKJ_W=&o7~yhhybhF; z=dn4$+2{~LqsJ*=bUVXC4nfuS&&Okp-U+F1Qh2|AQB035&@J5i$_8ckNJPXY!cja; zu^Z-f6i!d>3v6shtR<^4;ik!K#xX0%C1DqqNQKY3(-xU9#J8iupG zThNHyp9@@pAVYDu=HOWLQ`)Wb?oz|Kn6)gdTDMJP2k$W#tmnKA5I&6Q!+mM|iExC|`#Q_7`G7qfgzQ1FMXa{E&iOQRbdKs}<1omQaX8905cd6_jA4Xzdi< zZ5eB;wTi?30Vx24YG1qt`B0~J%B+3_Z~ykpMHA4e?uD{MW!q6a%Cke+^iGA(N;q0Y zkrE@;+$?O~xPBarNOuvU@A;w)>G%lu3Zi*QJo4H|r2^ zl`6gBGH3KS=w&VF2cSb4_5z@x$0l?Z{Yi-}Yn8(=8ADUr%|6wWSd(`DC0W9Eft>*L$-HSn14w%>bZD^7d-fm3l-4` zi&L`8juks7H{%F^y$}kS7M`}S_6`uJ4u48hrCe<+u|)-0dgK}TlJgot(MV*lAm4+- zNmm6AbfpzfsWprtZCD1uI}W8qDJX(M8*!8%)^uPe07A5iYe}}tc75q4!_Vxpuw4=X zDoo)_g4xB@mS=a+py4L{t8FLxHCs~t+N#&~8_Ao!J%SgEUt9KG_m;gDMuNGtYq8BP z{lN29MMKbijKL?MY1)s_P~_LO4b%84=<0CW#%V;qH3{F;mPc@((iXJFhC|pYNirLha=m ziWUV2_($N^6X{6+NVBcR&PvrC*pfYu4&tdIZV)+e3KCit%B+nuW5D7r3e@|_p1`zU zPg#WJo(g~Axr^)#FDDSVq#Nvj6LyD&e{!(LNQ0Kn;z2yeSC&(bU4wgMB!{2Z9kJAN z*Ws^_ZvlADn@gr$Ub4>u2v*fR%{p~?gQLg9pj2EN-BI1^#3Qh%l(BogoA?PJgXr&x+lH>C92l?8SlWFcWC)kZ+?5RUbt!(Sq zryv_5Qk0rOC!m!jZ(tlVQJMMxvB<=&&ATKabCO7tNz5h|8E@X&4-Z964iMsAD2J7) z?bXvps#u4qJmnXOGPsAntvae$eds>NZVW6sAU^*9hUX%<#d)D5tn{&ZbN`J_iE?47R1)`oW+`S8I#;$P{Uad@unh>s2eaY;C;b%KV z-nyF1qtxJOT!UT-Ut1^SIY5qt%3lFnr{QO-?K`--9AiU1eA4MC{(SFhlkqsGx}=rE z7=;=DUA8^@<$9}4q>Q067q0THG6Rq7coRR&i^>a+7Mi9($)ZCh48JD)sbHFlEYMHN zz2WMhxwsXU3nxc!hVaGSW3O$=Nh!~dH^VHmr{+$f#^2H27QsdUFh}=uK8o-)2am=$ zn@4^)ImqD-emiy|YmHSr_5>$$VYO(KVF)8mMNsVQ9o?5$uaURotQz|;iSA)ri$TCR zsLiQiNmClfL1{HkW}mZ>+}ECb)w#jjP~@4~w3)A8fUHEaz2+EK?r~+% zk;fXx)Ra|=4)s|uqjOSX)sbUxMAMLZrz)m_$1i(yjta5YTodUHS$st;M)U$IBbO;E z8#*dqK2wUfAvsrD#x7G*XHkmRjqGUMYHB3Ik>Vu3}g3& z)=B~1HCR)Oj{@fz(Vpr(-BKUX|vI^z;|Im8utLdU7P7>7q=#mOqAbxsYt{Rm3BqNETPDs6;sC1)9QN< z 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 diff --git a/core/gradle/wrapper/gradle-wrapper.properties b/core/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 9a6bf73b..00000000 --- a/core/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Sat Mar 02 11:11:32 CET 2019 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip diff --git a/core/gradlew b/core/gradlew deleted file mode 100644 index 91a7e269..00000000 --- a/core/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# 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 -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -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 - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - 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 -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "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 -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 - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # 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 - # 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\"" - fi - i=$((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" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/core/gradlew.bat b/core/gradlew.bat deleted file mode 100644 index 8a0b282a..00000000 --- a/core/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@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 - -@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= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@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 - -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 init - -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 - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_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=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -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% - -: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 diff --git a/core/settings.gradle b/core/settings.gradle deleted file mode 100644 index b698b033..00000000 --- a/core/settings.gradle +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2008-2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -rootProject.name='jd-core' - diff --git a/services/build.gradle b/services/build.gradle index 6ed884b9..77c7564f 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -3,7 +3,9 @@ apply plugin: 'java' dependencies { compile 'com.fifesoft:rsyntaxtextarea:3.0.4' compile 'org.ow2.asm:asm:7.1' - compile 'org.jd:jd-core:' + parent.jdCoreVersion + // put back if jd-core is going to be a separate artifact + // compile 'org.jd:jd-core:' + parent.jdCoreVersion + compile project(':core') compile project(':api') testCompile 'junit:junit:4.12' } diff --git a/settings.gradle b/settings.gradle index 6a2daca1..6a2b078a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ -include 'api', 'app', 'services' +include 'api', 'app', 'core', 'services' rootProject.name='jd-gui' From cba74c17b9c5cac3af1ea9ba06dc5651927bc228 Mon Sep 17 00:00:00 2001 From: Andrew Mu Date: Tue, 30 Apr 2024 09:40:34 -0700 Subject: [PATCH 210/211] make compatible with jdk9+ * https://github.com/tofi86/universalJavaApplicationStub to 3.3.0 * use new APIs for setOpenFileHandler and setQuitHandler on java 9+ --- app/src/main/java/org/jd/gui/OsxApp.java | 28 +- .../main/java/org/jd/gui/util/JavaUtil.java | 20 + .../resources/universalJavaApplicationStub.sh | 864 +++++++++++++++--- 3 files changed, 771 insertions(+), 141 deletions(-) create mode 100644 app/src/main/java/org/jd/gui/util/JavaUtil.java diff --git a/app/src/main/java/org/jd/gui/OsxApp.java b/app/src/main/java/org/jd/gui/OsxApp.java index b8ac598b..886faf69 100644 --- a/app/src/main/java/org/jd/gui/OsxApp.java +++ b/app/src/main/java/org/jd/gui/OsxApp.java @@ -8,20 +8,30 @@ package org.jd.gui; import com.apple.eawt.Application; +import org.jd.gui.util.JavaUtil; + +import java.awt.*; public class OsxApp extends App { - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "Since15"}) public static void main(String[] args) { - // Create an instance of the mac OSX Application class - Application application = Application.getApplication(); - - App.main(args); + if (JavaUtil.runtimeVersion() <= 8) { + // This method has been deprecated + // https://bugs.openjdk.org/browse/JDK-8160437 + // Create an instance of the mac OSX Application class + Application application = Application.getApplication(); - // Add an handle invoked when the application is asked to open a list of files - application.setOpenFileHandler(e -> controller.openFiles(e.getFiles())); + // Add an handle invoked when the application is asked to open a list of files + application.setOpenFileHandler(e -> controller.openFiles(e.getFiles())); - // Add an handle invoked when the application is asked to quit - application.setQuitHandler((e, r) -> System.exit(0)); + // Add an handle invoked when the application is asked to quit + application.setQuitHandler((e, r) -> System.exit(0)); + } else { + Desktop desktop = Desktop.getDesktop(); + desktop.setOpenFileHandler(e -> controller.openFiles(e.getFiles())); + desktop.setQuitHandler((e, r) -> System.exit(0)); + } + App.main(args); } } diff --git a/app/src/main/java/org/jd/gui/util/JavaUtil.java b/app/src/main/java/org/jd/gui/util/JavaUtil.java new file mode 100644 index 00000000..2c174873 --- /dev/null +++ b/app/src/main/java/org/jd/gui/util/JavaUtil.java @@ -0,0 +1,20 @@ +package org.jd.gui.util; + +public class JavaUtil { + /** + * Retrieves the "major" Java version + * 1.8.0_211 == 8, 9.0.1 = 9 + * From a post in + * https://stackoverflow.com/questions/2591083/getting-java-version-at-runtime + * @return an integer representing the major Java version of the runtime. + */ + public static int runtimeVersion() { + String version = System.getProperty("java.version"); + if(version.startsWith("1.")) { + version = version.substring(2, 3); + } else { + int dot = version.indexOf("."); + if(dot != -1) { version = version.substring(0, dot); } + } return Integer.parseInt(version); + } +} diff --git a/src/osx/resources/universalJavaApplicationStub.sh b/src/osx/resources/universalJavaApplicationStub.sh index 686db22d..cea7f12f 100644 --- a/src/osx/resources/universalJavaApplicationStub.sh +++ b/src/osx/resources/universalJavaApplicationStub.sh @@ -1,28 +1,24 @@ -#!/bin/sh +#!/bin/bash ################################################################################## # # # universalJavaApplicationStub # # # -# # -# A shellscript JavaApplicationStub for Java Apps on Mac OS X # +# A BASH based JavaApplicationStub for Java Apps on Mac OS X # # that works with both Apple's and Oracle's plist format. # # # # Inspired by Ian Roberts stackoverflow answer # # at http://stackoverflow.com/a/17546508/1128689 # # # -# # # @author Tobias Fischer # # @url https://github.com/tofi86/universalJavaApplicationStub # -# @date 2015-05-15 # -# @version 0.9.0 # -# # +# @date 2023-02-04 # +# @version 3.3.0 # # # ################################################################################## # # -# # # The MIT License (MIT) # # # -# Copyright (c) 2015 Tobias Fischer # +# Copyright (c) 2014-2023 Tobias Fischer # # # # Permission is hereby granted, free of charge, to any person obtaining a copy # # of this software and associated documentation files (the "Software"), to deal # @@ -46,40 +42,52 @@ - +# function 'stub_logger()' +# +# A logger which logs to the macOS Console.app using the 'syslog' command # -# resolve symlinks -##################### +# @param1 the log message +# @return void +################################################################################ +function stub_logger() { + syslog -s -k \ + Facility com.apple.console \ + Level Notice \ + Sender "$(basename "$0")" \ + Message "[$$][${CFBundleName:-$(basename "$0")}] $1" +} -PRG=$0 -while [ -h "$PRG" ]; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null` - if expr "$link" : '^/' 2> /dev/null >/dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi -done -# set the directory abspath of the current shell script -PROGDIR=`dirname "$PRG"` +# set the directory abspath of the current +# shell script with symlinks being resolved +############################################ +PRG=$0 +while [ -h "$PRG" ]; do + ls=$(ls -ld "$PRG") + link=$(expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null) + if expr "$link" : '^/' 2> /dev/null >/dev/null; then + PRG="$link" + else + PRG="$(dirname "$PRG")/$link" + fi +done +PROGDIR=$(dirname "$PRG") +stub_logger "[StubDir] $PROGDIR" -# # set files and folders ############################################ # the absolute path of the app package -cd "$PROGDIR"/../../ -AppPackageFolder=`pwd` +cd "$PROGDIR"/../../ || exit 11 +AppPackageFolder=$(pwd) # the base path of the app package -cd .. -AppPackageRoot=`pwd` +cd .. || exit 12 +AppPackageRoot=$(pwd) # set Apple's Java folder AppleJavaFolder="${AppPackageFolder}"/Contents/Resources/Java @@ -98,19 +106,43 @@ InfoPlistFile="${AppPackageFolder}"/Contents/Info.plist # set the default JVM Version to a null string JVMVersion="" +JVMMaxVersion="" +# function 'plist_get()' +# +# read a specific Plist key with 'PlistBuddy' utility +# +# @param1 the Plist key with leading colon ':' +# @return the value as String or Array +################################################################################ +plist_get(){ + /usr/libexec/PlistBuddy -c "print $1" "${InfoPlistFile}" 2> /dev/null +} + +# function 'plist_get_java()' +# +# read a specific Plist key with 'PlistBuddy' utility +# in the 'Java' or 'JavaX' dictionary () # +# @param1 the Plist :Java(X):Key with leading colon ':' +# @return the value as String or Array +################################################################################ +plist_get_java(){ + plist_get ${JavaKey:-":Java"}$1 +} + + + # read Info.plist and extract JVM options ############################################ - # read the program name from CFBundleName -CFBundleName=`/usr/libexec/PlistBuddy -c "print :CFBundleName" "${InfoPlistFile}"` +CFBundleName=$(plist_get ':CFBundleName') # read the icon file name -CFBundleIconFile=`/usr/libexec/PlistBuddy -c "print :CFBundleIconFile" "${InfoPlistFile}"` +CFBundleIconFile=$(plist_get ':CFBundleIconFile') # check Info.plist for Apple style Java keys -> if key :Java is present, parse in apple mode @@ -126,183 +158,751 @@ if [ $exitcode -ne 0 ]; then fi -# read Info.plist in Apple style if exit code returns 0 (true, :Java key is present) +# read 'Info.plist' file in Apple style if exit code returns 0 (true, ':Java' key is present) if [ $exitcode -eq 0 ]; then + stub_logger "[PlistStyle] Apple" # set Java and Resources folder JavaFolder="${AppleJavaFolder}" ResourcesFolder="${AppleResourcesFolder}" + # set expandable variables + APP_ROOT="${AppPackageFolder}" APP_PACKAGE="${AppPackageFolder}" JAVAROOT="${AppleJavaFolder}" USER_HOME="$HOME" # read the Java WorkingDirectory - JVMWorkDir=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:WorkingDirectory" "${InfoPlistFile}" 2> /dev/null | xargs` - - # set Working Directory based upon Plist info + JVMWorkDir=$(plist_get_java ':WorkingDirectory' | xargs) + # set Working Directory based upon PList value if [[ ! -z ${JVMWorkDir} ]]; then WorkingDirectory="${JVMWorkDir}" else # AppPackageRoot is the standard WorkingDirectory when the script is started WorkingDirectory="${AppPackageRoot}" fi - - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME - WorkingDirectory=`eval "echo ${WorkingDirectory}"` + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME + WorkingDirectory=$(eval echo "${WorkingDirectory}") # read the MainClass name - JVMMainClass=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:MainClass" "${InfoPlistFile}" 2> /dev/null` + JVMMainClass="$(plist_get_java ':MainClass')" - # read the JVM Options - JVMOptions=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:Properties" "${InfoPlistFile}" 2> /dev/null | grep " =" | sed 's/^ */-D/g' | tr '\n' ' ' | sed 's/ */ /g' | sed 's/ = /=/g' | xargs` + # read the SplashFile name + JVMSplashFile=$(plist_get_java ':SplashFile') - # read StartOnMainThread - JVMStartOnMainThread=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:StartOnMainThread" "${InfoPlistFile}" 2> /dev/null` - if [ "${JVMStartOnMainThread}" == "true" ]; then - echo ${JVMStartOnMainThread} > ~/Desktop/test.txt - JVMOptions+=" -XstartOnFirstThread" - fi + # read the JVM Properties as an array and retain spaces + IFS=$'\t\n' + JVMOptions=($(xargs -n1 <<<$(plist_get_java ':Properties' | grep " =" | sed 's/^ */-D/g' | sed -E 's/ = (.*)$/="\1"/g'))) + unset IFS + # post processing of the array follows further below... # read the ClassPath in either Array or String style - JVMClassPath_RAW=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null` + JVMClassPath_RAW=$(plist_get_java ':ClassPath' | xargs) if [[ $JVMClassPath_RAW == *Array* ]] ; then - JVMClassPath=.`/usr/libexec/PlistBuddy -c "print ${JavaKey}:ClassPath" "${InfoPlistFile}" 2> /dev/null | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs` + JVMClassPath=.$(plist_get_java ':ClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs) else JVMClassPath=${JVMClassPath_RAW} fi - # expand variables $APP_PACKAGE, $JAVAROOT, $USER_HOME - JVMClassPath=`eval "echo ${JVMClassPath}"` + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME + JVMClassPath=$(eval echo "${JVMClassPath}") + + # read the JVM Options in either Array or String style + JVMDefaultOptions_RAW=$(plist_get_java ':VMOptions' | xargs) + if [[ $JVMDefaultOptions_RAW == *Array* ]] ; then + JVMDefaultOptions=$(plist_get_java ':VMOptions' | grep " " | sed 's/^ */ /g' | tr -d '\n' | xargs) + else + JVMDefaultOptions=${JVMDefaultOptions_RAW} + fi + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#84) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") + + # read StartOnMainThread and add as -XstartOnFirstThread + JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread') + if [ "${JVMStartOnMainThread}" == "true" ]; then + JVMDefaultOptions+=" -XstartOnFirstThread" + fi - # read the JVM Default Options - JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:VMOptions" "${InfoPlistFile}" 2> /dev/null | xargs` + # read the JVM Arguments in either Array or String style (#76) and retain spaces + IFS=$'\t\n' + MainArgs_RAW=$(plist_get_java ':Arguments' | xargs) + if [[ $MainArgs_RAW == *Array* ]] ; then + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g'))) + else + MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments'))) + fi + unset IFS + # post processing of the array follows further below... - # read the JVM Arguments - JVMArguments=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:Arguments" "${InfoPlistFile}" 2> /dev/null | xargs` + # read the Java version we want to find + JVMVersion=$(plist_get_java ':JVMVersion' | xargs) + # post processing of the version string follows below... - # read the Java version we want to find - JVMVersion=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:JVMVersion" "${InfoPlistFile}" 2> /dev/null | xargs` -# read Info.plist in Oracle style +# read 'Info.plist' file in Oracle style else + stub_logger "[PlistStyle] Oracle" # set Working Directory and Java and Resources folder JavaFolder="${OracleJavaFolder}" ResourcesFolder="${OracleResourcesFolder}" WorkingDirectory="${OracleJavaFolder}" + # set expandable variables APP_ROOT="${AppPackageFolder}" + APP_PACKAGE="${AppPackageFolder}" + JAVAROOT="${OracleJavaFolder}" + USER_HOME="$HOME" # read the MainClass name - JVMMainClass=`/usr/libexec/PlistBuddy -c "print :JVMMainClassName" "${InfoPlistFile}" 2> /dev/null` + JVMMainClass="$(plist_get ':JVMMainClassName')" - # read the JVM Options - JVMOptions=`/usr/libexec/PlistBuddy -c "print :JVMOptions" "${InfoPlistFile}" 2> /dev/null | grep " -" | tr -d '\n' | sed 's/ */ /g' | xargs` - # replace occurances of $APP_ROOT with it's content - JVMOptions=`eval "echo ${JVMOptions}"` + # read the SplashFile name + JVMSplashFile=$(plist_get ':JVMSplashFile') - JVMClassPath="${JavaFolder}/*" + # read the JVM Options as an array and retain spaces + IFS=$'\t\n' + JVMOptions=($(plist_get ':JVMOptions' | grep " " | sed 's/^ *//g')) + unset IFS + # post processing of the array follows further below... - # read the JVM Default Options - JVMDefaultOptions=`/usr/libexec/PlistBuddy -c "print :JVMDefaultOptions" "${InfoPlistFile}" 2> /dev/null | grep -o "\-.*" | tr -d '\n' | xargs` + # read the ClassPath in either Array or String style + JVMClassPath_RAW=$(plist_get ':JVMClassPath') + if [[ $JVMClassPath_RAW == *Array* ]] ; then + JVMClassPath=.$(plist_get ':JVMClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs) + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME + JVMClassPath=$(eval echo "${JVMClassPath}") + + elif [[ ! -z ${JVMClassPath_RAW} ]] ; then + JVMClassPath=${JVMClassPath_RAW} + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME + JVMClassPath=$(eval echo "${JVMClassPath}") + + else + #default: fallback to OracleJavaFolder + JVMClassPath="${JavaFolder}/*" + # Do NOT expand the default 'AppName.app/Contents/Java/*' classpath (#42) + fi - # read the JVM Arguments - JVMArguments=`/usr/libexec/PlistBuddy -c "print :JVMArguments" "${InfoPlistFile}" 2> /dev/null | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g' | xargs` - # replace occurances of $APP_ROOT with it's content - JVMArguments=`eval "echo ${JVMArguments}"` + # read the JVM Default Options by parsing the :JVMDefaultOptions + # and pulling all values starting with a dash (-) + JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs) + # expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#99) + JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}") + + # read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details) + IFS=$'\t\n' + MainArgs=($(xargs -n1 <<<$(plist_get ':JVMArguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g'))) + unset IFS + # post processing of the array follows further below... + + # read the Java version we want to find + JVMVersion=$(plist_get ':JVMVersion' | xargs) + # post processing of the version string follows below... fi +# (#75) check for undefined icons or icon names without .icns extension and prepare +# an osascript statement for those cases when the icon can be shown in the dialog +DialogWithIcon="" +if [ ! -z ${CFBundleIconFile} ]; then + if [[ ${CFBundleIconFile} == *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}" ]] ; then + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + elif [[ ${CFBundleIconFile} != *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}.icns" ]] ; then + CFBundleIconFile+=".icns" + DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + fi +fi + + +# JVMVersion: post processing and optional splitting +if [[ ${JVMVersion} == *";"* ]]; then + minMaxArray=(${JVMVersion//;/ }) + JVMVersion=${minMaxArray[0]//+} + JVMMaxVersion=${minMaxArray[1]//+} +fi +stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}" +stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}" + +# MainArgs: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME +MainArgsArr=() +for i in "${MainArgs[@]}" +do + MainArgsArr+=("$(eval echo "$i")") +done + +# JVMOptions: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME +JVMOptionsArr=() +for i in "${JVMOptions[@]}" +do + JVMOptionsArr+=("$(eval echo "$i")") +done + + +# internationalized messages +############################################ + +# supported languages / available translations +stubLanguages=("de" "en" "es" "fr" "pt-BR" "zh") + +# read user preferred languages as defined in macOS System Preferences (#101) +stub_logger '[LanguageSearch] Checking preferred languages in macOS System Preferences...' +appleLanguages=($(defaults read -g AppleLanguages | grep '\s"' | tr -d ',' | xargs)) +stub_logger "[LanguageSearch] ... found [${appleLanguages[*]}]" + +language="" +for i in "${appleLanguages[@]}" +do + langValue="${i%-*}" + if [[ " ${stubLanguages[*]} " =~ " ${i} " ]]; then + stub_logger "[LanguageSearch] ... selected '$i' as the default language for the launcher stub" + language=${i} + break + elif [[ " ${stubLanguages[*]} " =~ " ${langValue} " ]]; then + stub_logger "[LanguageSearch] ... selected '$langValue' (from '$i') as the default language for the launcher stub" + language=${langValue} + break + fi +done +if [ -z "${language}" ]; then + language="en" + stub_logger "[LanguageSearch] ... selected fallback 'en' as the default language for the launcher stub" +fi +stub_logger "[Language] $language" + + +case "${language}" in +# French +fr) + MSG_ERROR_LAUNCHING="ERREUR au lancement de '${CFBundleName}'." + MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée." + MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version de Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application." + MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s" + MSG_JAVA_VERSION_OR_LATER="ou ultérieur" + MSG_JAVA_VERSION_LATEST="(dernière mise à jour)" + MSG_JAVA_VERSION_MAX="à %s" + MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise." + MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..." + MSG_LATER="Plus tard" + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTIUM="Java by Adoptium" + ;; + +# German +de) + MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'." + MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!" + MSG_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App." + MSG_NO_SUITABLE_JAVA="Es wurde keine passende Java-Version auf Ihrem System gefunden!\nDieses Programm benötigt Java %s" + MSG_JAVA_VERSION_OR_LATER="oder neuer" + MSG_JAVA_VERSION_LATEST="(neuste Unterversion)" + MSG_JAVA_VERSION_MAX="bis %s" + MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist." + MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise." + MSG_LATER="Später" + MSG_VISIT_JAVA_DOT_COM="Java von Oracle" + MSG_VISIT_ADOPTIUM="Java von Adoptium" + ;; + +# Simplified Chinese +zh) + MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'." + MSG_MISSING_MAINCLASS="没有指定 'MainClass'!\nJava程序无法启动!" + MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。" + MSG_NO_SUITABLE_JAVA="没有在系统中找到合适的Java版本!\n必须安装Java %s才能够使用该程序!" + MSG_JAVA_VERSION_OR_LATER="及以上版本" + MSG_JAVA_VERSION_LATEST="(最新版本)" + MSG_JAVA_VERSION_MAX="最高为 %s" + MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本" + MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境!\n访问 java.com 了解如何安装。" + MSG_LATER="稍后" + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTIUM="Java by Adoptium" + ;; + +# Spanish +es) + MSG_ERROR_LAUNCHING="ERROR iniciando '${CFBundleName}'." + MSG_MISSING_MAINCLASS="¡'MainClass' no especificada!\n¡La aplicación Java no puede iniciarse!" + MSG_JVMVERSION_REQ_INVALID="La sintaxis de la versión Java requerida no es válida: %s\nPor favor, contacte con el desarrollador de la aplicación." + MSG_NO_SUITABLE_JAVA="¡No se encontró una versión de Java adecuada en su sistema!\nEste programa requiere Java %s" + MSG_JAVA_VERSION_OR_LATER="o posterior" + MSG_JAVA_VERSION_LATEST="(ultima actualización)" + MSG_JAVA_VERSION_MAX="superior a %s" + MSG_NO_SUITABLE_JAVA_CHECK="Asegúrese de instalar la versión Java requerida." + MSG_INSTALL_JAVA="¡Necesita tener JAVA instalado en su Mac!\nVisite java.com para consultar las instrucciones para su instalación..." + MSG_LATER="Más tarde" + MSG_VISIT_JAVA_DOT_COM="Java de Oracle" + MSG_VISIT_ADOPTIUM="Java de Adoptium" + ;; + +# Brazilian Portuguese +pt-BR) + MSG_ERROR_LAUNCHING="ERRO iniciando '${CFBundleName}'." + MSG_MISSING_MAINCLASS="'MainClass' não foi definida!\nA aplicação java não poderá ser iniciada!" + MSG_JVMVERSION_REQ_INVALID="A sintaxe da versão Java requerida não é valida: %s\nPor favor contacte o desenvolvedor dessa aplicação." + MSG_NO_SUITABLE_JAVA="Não foi encontrado uma versão Java compatível no seu sistema!\nEsta aplicação precisa do Java %s" + MSG_JAVA_VERSION_OR_LATER="ou maior" + MSG_JAVA_VERSION_LATEST="(última atualização)" + MSG_JAVA_VERSION_MAX="máxima %s" + MSG_NO_SUITABLE_JAVA_CHECK="Verifique se instalou a versão Java necessária." + MSG_INSTALL_JAVA="Você precisa instalar o JAVA no seu Mac!\nPor favor, visite java.com para instruções de instalação..." + MSG_LATER="Depois" + MSG_VISIT_JAVA_DOT_COM="Java por Oracle" + MSG_VISIT_ADOPTIUM="Java por Adoptium" + ;; + +# English | default +en|*) + MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'." + MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!" + MSG_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer." + MSG_NO_SUITABLE_JAVA="No suitable Java version found on your system!\nThis program requires Java %s" + MSG_JAVA_VERSION_OR_LATER="or later" + MSG_JAVA_VERSION_LATEST="(latest update)" + MSG_JAVA_VERSION_MAX="up to %s" + MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version." + MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..." + MSG_LATER="Later" + MSG_VISIT_JAVA_DOT_COM="Java by Oracle" + MSG_VISIT_ADOPTIUM="Java by Adoptium" + ;; +esac + + + +# function 'get_java_version_from_cmd()' +# +# returns Java version string from 'java -version' command +# works for both old (1.8) and new (9) version schema +# +# @param1 path to a java JVM executable +# @return the Java version number as displayed in 'java -version' command +################################################################################ +function get_java_version_from_cmd() { + # second sed command strips " and -ea from the version string + echo $("$1" -version 2>&1 | awk '/version/{print $3}' | sed -E 's/"//g;s/-ea//g') +} +# function 'extract_java_major_version()' +# +# extract Java major version from a version string # -# find installed Java versions -################################# +# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+') +# @return the major version (e.g. '7', '8' or '9', etc.) +################################################################################ +function extract_java_major_version() { + echo $(echo "$1" | sed -E 's/^1\.//;s/^([0-9]+)(-ea|(\.[0-9_.]{1,7})?)(-b[0-9]+-[0-9]+)?[+*]?$/\1/') +} -# first check system variable "$JAVA_HOME" -if [ -n "$JAVA_HOME" ] ; then - JAVACMD="$JAVA_HOME/bin/java" - -# check for specified JVMversion in "/usr/libexec/java_home" symlinks -elif [ ! -z ${JVMVersion} ] && [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F; then - if /usr/libexec/java_home -F -v ${JVMVersion}; then - JAVACMD="`/usr/libexec/java_home -F -v ${JVMVersion} 2> /dev/null`/bin/java" +# function 'get_comparable_java_version()' +# +# return comparable version for a Java version number or requirement string +# +# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+') +# @return an 8 digit numeral ('1.8.0_45'->'08000045'; '9.1.13'->'09001013') +################################################################################ +function get_comparable_java_version() { + # cleaning: 1) remove leading '1.'; 2) remove build string (e.g. '-b14-468'); 3) remove 'a-Z' and '-*+' (e.g. '-ea'); 4) replace '_' with '.' + local cleaned=$(echo "$1" | sed -E 's/^1\.//g;s/-b[0-9]+-[0-9]+$//g;s/[a-zA-Z+*\-]//g;s/_/./g') + # splitting at '.' into an array + local arr=( ${cleaned//./ } ) + # echo a string with left padded version numbers + echo "$(printf '%02s' ${arr[0]})$(printf '%03s' ${arr[1]})$(printf '%03s' ${arr[2]})" +} + + +# function 'is_valid_requirement_pattern()' +# +# check whether the Java requirement is a valid requirement pattern +# +# supported requirements are for example: +# - 1.6 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88] +# - 1.6* requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88] +# - 1.6+ requires Java 6 or higher [1.6, 1.6.0_45, 1.8, 9, etc.] +# - 1.6.0 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88] +# - 1.6.0_45 requires Java 6u45 [1.6.0_45] +# - 1.6.0_45+ requires Java 6u45 or higher [1.6.0_45, 1.6.0_88, 1.8, etc.] +# - 9 requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.] +# - 9* requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.] +# - 9+ requires Java 9 or higher [9.0, 9.1, 10, etc.] +# - 9.1 requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.] +# - 9.1* requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.] +# - 9.1+ requires Java 9.1 or higher [9.1, 9.2, 10, etc.] +# - 9.1.3 requires Java 9.1.3 [9.1.3] +# - 9.1.3* requires Java 9.1.3 (any update) [9.1.3] +# - 9.1.3+ requires Java 9.1.3 or higher [9.1.3, 9.1.4, 9.2.*, 10, etc.] +# - 10-ea requires Java 10 (early access release) +# +# unsupported requirement patterns are for example: +# - 1.2, 1.3, 1.9 Java 2, 3 are not supported +# - 1.9 Java 9 introduced a new versioning scheme +# - 6u45 known versioning syntax, but unsupported +# - 9-ea*, 9-ea+ early access releases paired with */+ +# - 9., 9.*, 9.+ version ending with a . +# - 9.1., 9.1.*, 9.1.+ version ending with a . +# - 9.3.5.6 4 part version number is unsupported +# +# @param1 a Java requirement string ('1.8+') +# @return boolean exit code: 0 (is valid), 1 (is not valid) +################################################################################ +function is_valid_requirement_pattern() { + local java_req=$1 + java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?' + java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?' + # test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9) + if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then + return 0 else - # display error message with applescript - osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'\n\nNo suitable Java version found on your system!\nThis program requires Java ${JVMVersion}\nMake sure you install the required Java version.\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" - # exit with error - exit 3 + return 1 fi +} + -# otherwise check "/usr/libexec/java_home" symlinks -elif [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F; then - JAVACMD="`/usr/libexec/java_home 2> /dev/null`/bin/java" -# otherwise check Java standard symlink (old Apple Java) -elif [ -h /Library/Java/Home ]; then - JAVACMD="/Library/Java/Home/bin/java" +# determine which JVM to use +############################################ -# fallback: public JRE plugin (Oracle Java) +# default Apple JRE plugin path (< 1.6) +apple_jre_plugin="/Library/Java/Home/bin/java" +apple_jre_version=$(get_java_version_from_cmd "${apple_jre_plugin}") +# default Oracle JRE plugin path (>= 1.7) +oracle_jre_plugin="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java" +oracle_jre_version=$(get_java_version_from_cmd "${oracle_jre_plugin}") + + +# first check system variable "$JAVA_HOME" -> has precedence over any other System JVM +stub_logger '[JavaSearch] Checking for $JAVA_HOME ...' +if [ -n "$JAVA_HOME" ] ; then + stub_logger "[JavaSearch] ... found JAVA_HOME with value $JAVA_HOME" + + # PR 26: Allow specifying "$JAVA_HOME" relative to "$AppPackageFolder" + # which allows for bundling a custom version of Java inside your app! + if [[ $JAVA_HOME == /* ]] ; then + # if "$JAVA_HOME" starts with a Slash it's an absolute path + JAVACMD="$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as absolute path to the executable '$JAVACMD'" + else + # otherwise it's a relative path to "$AppPackageFolder" + JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java" + stub_logger "[JavaSearch] ... parsing JAVA_HOME as relative path inside the App bundle to the executable '$JAVACMD'" + fi + JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}")) else - JAVACMD="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java" + stub_logger "[JavaSearch] ... haven't found JAVA_HOME" fi -# fallback fallback: /usr/bin/java -# but this would prompt to install deprecated Apple Java 6 +# check for any other or a specific Java version +# also if $JAVA_HOME exists but isn't executable +if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then + # add a warning in the syslog if JAVA_HOME is not executable or not found (#100) + if [ -n "$JAVA_HOME" ] ; then + stub_logger "[JavaSearch] ... but no 'java' executable was found at the JAVA_HOME location!" + fi + stub_logger "[JavaSearch] Searching for JavaVirtualMachines on the system ..." + # reset variables + JAVACMD="" + JAVACMD_version="" + + # first check whether JVMVersion string is a valid requirement string + if [ ! -z "${JVMVersion}" ] && ! is_valid_requirement_pattern ${JVMVersion} ; then + MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMVersion}") + # log exit cause + stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" + # display error message with AppleScript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" + # exit with error + exit 4 + fi + # then check whether JVMMaxVersion string is a valid requirement string + if [ ! -z "${JVMMaxVersion}" ] && ! is_valid_requirement_pattern ${JVMMaxVersion} ; then + MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMMaxVersion}") + # log exit cause + stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}" + # display error message with AppleScript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" + # exit with error + exit 5 + fi -# -# execute JAVA commandline and do some pre-checks -#################################################### -# display error message if MainClassName is empty -if [ -z ${JVMMainClass} ]; then - # display error message with applescript - osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'!\n\n'MainClass' isn't specified!\nJava application cannot be started!\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" - # exit with error - exit 2 + # find installed JavaVirtualMachines (JDK + JRE) + allJVMs=() + + # read JDK's from '/usr/libexec/java_home --xml' command with PlistBuddy and a custom Dict iterator + # idea: https://stackoverflow.com/a/14085460/1128689 and https://scriptingosx.com/2018/07/parsing-dscl-output-in-scripts/ + javaXml=$(/usr/libexec/java_home --xml) + javaCounter=$(/usr/libexec/PlistBuddy -c "Print" /dev/stdin <<< $javaXml | grep "Dict" | wc -l | tr -d ' ') + + # iterate over all Dict entries + # but only if there are any JVMs at all (#93) + if [ "$javaCounter" -gt "0" ] ; then + for idx in $(seq 0 $((javaCounter - 1))) + do + version=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMVersion" /dev/stdin <<< $javaXml) + path=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMHomePath" /dev/stdin <<< $javaXml) + path+="/bin/java" + allJVMs+=("$version:$path") + done + # unset for loop variables + unset version path + fi + # add SDKMAN! java versions (#95) + if [ -d ~/.sdkman/candidates/java/ ] ; then + for sdkjdk in ~/.sdkman/candidates/java/*/ + do + if [[ ${sdkjdk} =~ /current/$ ]] ; then + continue + fi + + sdkjdkcmd="${sdkjdk}bin/java" + version=$(get_java_version_from_cmd "${sdkjdkcmd}") + allJVMs+=("$version:$sdkjdkcmd") + done + # unset for loop variables + unset version + fi + + # add Apple JRE if available + if [ -x "${apple_jre_plugin}" ] ; then + allJVMs+=("$apple_jre_version:$apple_jre_plugin") + fi + + # add Oracle JRE if available + if [ -x "${oracle_jre_plugin}" ] ; then + allJVMs+=("$oracle_jre_version:$oracle_jre_plugin") + fi + + # debug output + for i in "${allJVMs[@]}" + do + stub_logger "[JavaSearch] ... found JVM: $i" + done + + + # determine JVMs matching the min/max version requirement + + stub_logger "[JavaSearch] Filtering the result list for JVMs matching the min/max version requirement ..." + + minC=$(get_comparable_java_version ${JVMVersion}) + maxC=$(get_comparable_java_version ${JVMMaxVersion}) + matchingJVMs=() + + for i in "${allJVMs[@]}" + do + # split JVM string at ':' delimiter to retain spaces in $path substring + IFS=: arr=($i) ; unset IFS + # [0] JVM version number + ver=${arr[0]} + # comparable JVM version number + comp=$(get_comparable_java_version $ver) + # [1] JVM path + path="${arr[1]}" + # construct string item for adding to the "matchingJVMs" array + item="$comp:$ver:$path" + + # pre-requisite: current version number needs to be greater than min version number + if [ "$comp" -ge "$minC" ] ; then + + # perform max version checks if max version requirement is present + if [ ! -z ${JVMMaxVersion} ] ; then + + # max version requirement ends with '*' modifier + if [[ ${JVMMaxVersion} == *\* ]] ; then + + # use the '*' modifier from the max version string as wildcard for a 'starts with' comparison + # and check whether the current version number starts with the max version wildcard string + if [[ ${ver} == ${JVMMaxVersion} ]]; then + matchingJVMs+=("$item") + + # or whether the current comparable version is lower than the comparable max version + elif [ "$comp" -le "$maxC" ] ; then + matchingJVMs+=("$item") + fi + + # max version requirement ends with '+' modifier -> always add this version if it's greater than $min + # because a max requirement with + modifier doesn't make sense + elif [[ ${JVMMaxVersion} == *+ ]] ; then + matchingJVMs+=("$item") + + # matches 6 zeros at the end of the max version string (e.g. for 1.8, 9) + # -> then the max version string should be treated like with a '*' modifier at the end + #elif [[ ${maxC} =~ ^[0-9]{2}0{6}$ ]] && [ "$comp" -le $(( ${maxC#0} + 999 )) ] ; then + # matchingJVMs+=("$item") + + # matches 3 zeros at the end of the max version string (e.g. for 9.1, 10.3) + # -> then the max version string should be treated like with a '*' modifier at the end + #elif [[ ${maxC} =~ ^[0-9]{5}0{3}$ ]] && [ "$comp" -le "${maxC}" ] ; then + # matchingJVMs+=("$item") + + # matches standard requirements without modifier + elif [ "$comp" -le "$maxC" ]; then + matchingJVMs+=("$item") + fi + + # no max version requirement: + + # min version requirement ends with '+' modifier + # -> always add the current version because it's greater than $min + elif [[ ${JVMVersion} == *+ ]] ; then + matchingJVMs+=("$item") + + # min version requirement ends with '*' modifier + # -> use the '*' modifier from the min version string as wildcard for a 'starts with' comparison + # and check whether the current version number starts with the min version wildcard string + elif [[ ${JVMVersion} == *\* ]] ; then + if [[ ${ver} == ${JVMVersion} ]] ; then + matchingJVMs+=("$item") + fi + + # compare the min version against the current version with an additional * wildcard for a 'starts with' comparison + # -> e.g. add 1.8.0_44 when the requirement is 1.8 + elif [[ ${ver} == ${JVMVersion}* ]] ; then + matchingJVMs+=("$item") + fi + fi + done + # unset for loop variables + unset arr ver comp path item + + # debug output + for i in "${matchingJVMs[@]}" + do + stub_logger "[JavaSearch] ... matches all requirements: $i" + done + + + # sort the matching JavaVirtualMachines by version number + # https://stackoverflow.com/a/11789688/1128689 + IFS=$'\n' matchingJVMs=($(sort -nr <<<"${matchingJVMs[*]}")) + unset IFS + + + # get the highest matching JVM + for ((i = 0; i < ${#matchingJVMs[@]}; i++)); + do + # split JVM string at ':' delimiter to retain spaces in $path substring + IFS=: arr=(${matchingJVMs[$i]}) ; unset IFS + # [0] comparable JVM version number + comp=${arr[0]} + # [1] JVM version number + ver=${arr[1]} + # [2] JVM path + path="${arr[2]}" + + # use current value as JAVACMD if it's executable + if [ -x "$path" ] ; then + JAVACMD="$path" + JAVACMD_version=$comp + break + fi + done + # unset for loop variables + unset arr comp ver path +fi -# check whether $JAVACMD is a file and executable -elif [ -f "$JAVACMD" ] && [ -x "$JAVACMD" ] ; then +# log the Java Command and the extracted version number +stub_logger "[JavaCommand] '$JAVACMD'" +stub_logger "[JavaVersion] $(get_java_version_from_cmd "${JAVACMD}")${JAVACMD_version:+ / $JAVACMD_version}" - # enable drag&drop to the dock icon - export CFProcessPath="$0" - # change to Working Directory based upon Apple/Oracle Plist info - cd "${WorkingDirectory}" - # execute Java and set - # - classpath - # - dock icon - # - application name - # - JVM options - # - JVM default options - # - main class - # - JVM arguments - exec "$JAVACMD" \ - -cp "${JVMClassPath}" \ - -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ - -Xdock:name="${CFBundleName}" \ - ${JVMOptions:+$JVMOptions }\ - ${JVMDefaultOptions:+$JVMDefaultOptions }\ - ${JVMMainClass}\ - ${JVMArguments:+ $JVMArguments} +if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then + # different error messages when a specific JVM was required + if [ ! -z "${JVMVersion}" ] ; then + # display human readable java version (#28) + java_version_hr=$(echo ${JVMVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+/ ${MSG_JAVA_VERSION_OR_LATER}/;s/*/ ${MSG_JAVA_VERSION_LATEST}/") + MSG_NO_SUITABLE_JAVA_EXPANDED=$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}"). -else + if [ ! -z "${JVMMaxVersion}" ] ; then + java_version_hr=$(extract_java_major_version ${JVMVersion}) + java_version_max_hr=$(echo ${JVMMaxVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+//;s/*/ ${MSG_JAVA_VERSION_LATEST}/") + MSG_NO_SUITABLE_JAVA_EXPANDED="$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}") $(printf "${MSG_JAVA_VERSION_MAX}" "${java_version_max_hr}")" + fi - # display error message with applescript - osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'!\n\nYou need to have JAVA installed on your Mac!\nVisit http://java.com for more information...\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)" + # log exit cause + stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}" - # and open java.com - open http://java.com + # display error message with AppleScript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTIUM}\"} default button 1${DialogWithIcon}" \ + -e "set response to button returned of the result" \ + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTIUM}\" then open location \"https://adoptium.net/releases.html\"" + # exit with error + exit 3 + + else + # log exit cause + stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}" + # display error message with AppleScript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTIUM}\"} default button 1${DialogWithIcon}" \ + -e "set response to button returned of the result" \ + -e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \ + -e "if response is \"${MSG_VISIT_ADOPTIUM}\" then open location \"https://adoptium.net/releases.html\"" + # exit with error + exit 1 + fi +fi + + +# MainClass check +############################################ + +if [ -z "${JVMMainClass}" ]; then + # log exit cause + stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}" + # display error message with AppleScript + osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}" # exit with error - exit 1 + exit 2 +fi + + + +# execute $JAVACMD and do some preparation +############################################ + +# enable drag&drop to the dock icon +export CFProcessPath="$0" + +# remove Apples ProcessSerialNumber from passthru arguments (#39) +if [[ "$*" == -psn* ]] ; then + ArgsPassthru=() +else + ArgsPassthru=("$@") fi + +# change to Working Directory based upon Apple/Oracle Plist info +cd "${WorkingDirectory}" || exit 13 +stub_logger "[WorkingDirectory] ${WorkingDirectory}" + +# execute Java and set +# - classpath +# - splash image +# - dock icon +# - app name +# - JVM options / properties (-D) +# - JVM default options (-X) +# - main class +# - main class arguments +# - passthrough arguments from Terminal or Drag'n'Drop to Finder icon +stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" ${JVMSplashFile:+ -splash:\"${ResourcesFolder}/${JVMSplashFile}\"} -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}" +exec "${JAVACMD}" \ + -cp "${JVMClassPath}" \ + ${JVMSplashFile:+ -splash:"${ResourcesFolder}/${JVMSplashFile}"} \ + -Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \ + -Xdock:name="${CFBundleName}" \ + ${JVMOptionsArr:+"${JVMOptionsArr[@]}" }\ + ${JVMDefaultOptions:+$JVMDefaultOptions }\ + "${JVMMainClass}"\ + ${MainArgsArr:+ "${MainArgsArr[@]}"}\ + ${ArgsPassthru:+ "${ArgsPassthru[@]}"} \ No newline at end of file From dde6dc5289a60596de315ebe4681d03c2439e4b2 Mon Sep 17 00:00:00 2001 From: Andrew Mu Date: Thu, 5 Dec 2024 21:31:23 -0800 Subject: [PATCH 211/211] bump jd-gui patch version to 1.6.7-rc1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b2c31a9f..4cd16fe6 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: 'edu.sc.seis.launch4j' apply plugin: 'nebula.ospackage' // Common configuration // -rootProject.version='1.6.6' +rootProject.version='1.6.7-rc1' rootProject.ext.set('jdCoreVersion', '1.1.3') targetCompatibility = '1.8'

-AsJD0}7+iNy5Im@q*|N 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip b/src/test/resources/zip/data-java-jdk-1.7.0-no-debug-info.zip new file mode 100644 index 0000000000000000000000000000000000000000..03b520b7d1530fd3770cd71c695a602bcdbe7613 GIT binary patch literal 4330 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jdk-1.8.0.zip b/src/test/resources/zip/data-java-jdk-1.8.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..d5a4c9096a49da26a5493f9b14ad32e074d2a9cc GIT binary patch literal 67076 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jdk-10.0.2.zip b/src/test/resources/zip/data-java-jdk-10.0.2.zip new file mode 100644 index 0000000000000000000000000000000000000000..cc2e8a1eecf4f0285828f055eb1b1fc840cca09a GIT binary patch literal 14644 zcmb7r1yEkuvMw5&;O_4365QS0-Q7L7LvVL@x1c|+!GpWI1QPTybI#nu%$a%jy-gLp zcU4z^z1QEnSFaX%DNryJpx-W^@=&{C{DB z{ST9ooukP+PWit8BL0Qb*~H2Df7l^`hy(TA_h}z90hu;rt!Dpn;Qx5uK5> zfs<3T8iX>j3QDKYsB{Pgp|At^Vr_nXctkxGFO517ZzM=Eg;jrF>bM|@u{~3%)kWw1 zy31L0WaP=R*KhY7c)Z8Y%o6-zcw3hT&#!uZ_nnw{uTH<#fDC`Ch_KRK<{_d->=D&< zst=I1DvJQ6gg1=&w1TKnwMq`ms~2vj6Oh`;+ZSxMN(@Y>)9j#uOQA%S?RKk((m_J) zK-(tNN%x*XC&P%ih3(0H%*1cv#~}zh|KiXR!KF>Wb`N>1TenJ{{HVfp=^q8r8R~tL z@?5Y>?;xv%DFcH&jy z3BoZ_Mu`c}4krse1$=hWRb~*sEc>ixu^PLR1#yRxStyu=6%=(N_EKh%NtG@wbGeuN z{iUc@wsRU~Zw6yMC^pMpI48DboKs+kg$+u9zV>JGtR}YgAmFEV2+$?W}r%iMy`E?lyNfeo6A(gyg8w zw0Pi?-(mBISx%@5XUu*69o@3QLWASzGp0drz<43aPbE*L zg0%F3T*?#MLloB{mXS;oTLPN1qO$^4)5cSNqt*PMJ=zD=;a4Q=1a=(+r)xNM*25H~ zOes4$dn8+~4s0#;}-k=^2+n!* zbYe4_G7k|;l2BTtS&LumV`&OTTCh#6c5#)ELUK~dX4)RCwS~JD?;C`hHKZow><|Xw zfwg^oP7~hZ?UY^tk~&_YBUs%|PR2Q25WOZ&!d;}Bm7kcK6eaF;f+z}BhdXBW{3ro#3j@+!8CPG6!koc*+%uI~`T6{Wys zhL1ExEh9Ph)W}NV3?1JjNzzj2MVA~d3xBAZl5E6(!X_=d+w65-L{2ODLS1SCFg2j6 zkc4Csm|Hz!F>;}tcR;L~`7*w%B^QldV5+!5MQf;RLwy28$miNG>uVit^K>ZKf-JEEdo(yUiVxY23*UNA#_GjMqjv5D1I=J%v@^4nD3#jQ zfEM)n-45>8F>gyRGJxcFd{qE-kk6Ke0cYk6`p+x8^^~gseEe;ivmX5*!$a;{2CnTFkh5h3yS$dRHYak|2uPl zq2tPq_X_wc4WKWx=p%FZVCevnE9$8&IT;;ui50-fqOzY6b=inBp-8)|_(yzT0$JYeN__H#D*j&4%hBZSsRt&dp;CA);a& zhg=OBYmG29vk6X-veJk4o^IL6GA6g$oy6*W4SvY04qIWmpF8JvGph4-#*DWuq|D;F z#no^8evujM``zTlYzWRjC0hkXXf_rE-X;Tew>5v}MH6>o`YzXk5x7lBmiK&Gm*ZNp zJau+6g?oMAphd@@m6@;Y)rRd4gOuYEzd|4al0hS)LGrBurCQt==iI>^#AfG`F4#Nr zY|y*9As5nx1*0%SMHz#r3CT}wu-ut%{CV;-Kp_gubxTQ5Z`z!jHN0b#RQ_|9L+Q50 zehBUmCXD%{xg!`B$40_Lw2z|XFTH|cUSG`4nNLc-#RCsHlfFA4dwVF+o%ET z{X79pM(aJkWAgD~ZODvrMElVrz5MwaGAxhjr~*}+Z7=~r)asaWt%1Gn`E5kgU$>c* zNz4K@6DTM(6g7brR^;)8Z4 zjAU!c8b`F3cTRX%__gs{D0rdq@>2Eyp0S`2m|%KhY_eA!I%QJw!Vp54x5!>dQ+Iqm*Zf`MKe$M?}Bx?=xpjld6jP!inQ4stK z?y$JN62!D$csB(4RqFT-BaMA4lLJQE$N7UiZELj=fRiX*Hk~GdCa?BN>ID40p;W#v zp4BQRRPol=#nA6eUk;CjBHe8Q76NYz#5U2y^B zMx}(E73HXh=?IpylSg%k*Y_=Rs@pYyGKEi#MX4c%`CjV!2xQP@2qhD+lj$yyH8N?- zRhSm^Z4aqoBub3JmiVTd_Md+l_x;oc`RTZ>E%a?&JdSR_KdY-YAqqq7bM`8ogiO-9uzjZo zL1&$+73&@vO#OI{If`#D#k3ULui#<6A%@7F<8;BVv&}YstQo?pX*EVCqT-D6<3K1G zO@ORze|veBU57ST7y5$eXF)}@QPr==7tfI{%E4|lZ|ztUup#6<^4cA_U2nd$XFq78 zPf1-_gT6d#G0cJuz7IZ)XD+rW-sWclAj1CQ;{e zUr*Op!=WdlK7r^lEH^h(Z%(V3w1f@5~2RdC|f zGiR4cmt~Ipkv#%?cfhHAD>b!=)I?(@zV zrJ{@Os*Et1lNC?C6Hjwzaj#Cdxiz{mga;Aefe{kcwIugPq7wx{tP7K5^LSit&If`) z(U-oqNonC?A8~H{nsn=az3?_mOX17rA+w ziw`NG%PT6pMWZaJt=n@x@=Bx;>kUd?!aX~WDsGIzncu6#vzcu^SD0~(BDO2BupPa1 zLJ8|fUYqfyOi!L$n|8rnbCir_)PY|TG*QBSRMt6)Pr;QQ>1@w0V+^ABIdC=0&rARV z@}cQO(eeVTY%zZa&cqZdnKh6&)?~1Q<65H`buXrW2bpkFzPQem3uHH2x3hafR>_JU zoLW04e#a7;WlTWne6hZrk+ILQdgXh*YjdTI)%=`nFfD0hyU4cnG@vpr0Jy0rpH@wo zGVA=H49=FMW)DI2k&yW=XU}mA95jtHVT8xLV!&(T^Ur3(oVe<)-Q`B|0^B$* zDv*`OhW1rZ#Hx>5LK9W0jfW3W`NwCTqRF0yG!y*ncVAPYXQ;X&Nk$cq?Jou;3K&^1 z+=8F6g>k46mOZ2L4>@noi^cla0=IGr%`0F_QbO{7qyeMk8XVSHV;T5(Lrv4&M&FMp z9C(YFi-qeb8--~Xo@p=>a=i-%Rh4fQwPcQUn!T9+fU-?0T2_cyKgC*Ds zJ`jdMehI4~FcxHhaUh1P6*b0!i({|`R>1ZsM`B!-}vB&E4ncTcC?*SfU$qh+!_j8Yz`g zXjG2ALdf#3mlJFrLCB17kqf+a7UI$0XB|L9ZL~ySV?V|ASkh%flc?4rxyhPH!X~-) zC~u}z*V75PPv-O{41G@M81cXh{rwEd#yOqy|l(iMa=5}aoh{Be6NVof6)yrxeSfJH#?d!>Q7xwkLY+O=4G4Ryt6yXo>cY) z;i7A9PU9@~@%D*PtWxZ`Q7X;A2)3W?%`K{Wt*SrO6-$}VzsW{@QI^4#7f&ji6Dm4F zM-6r0m!z5upjz?K=~g@HE5)X=ptyY!3I-r%8kVg##3;^m3El-D>2RjgKzm@(JXBoo zB0hV^2v5`RnwK8l?^1q-n@|coteI32@82b;OV+)8Fk1~#ajCde-?c-Kk)#jFn@A_^4V=3z&&Yi!Cg89FZN8K z>TWHdT-l*!N2s(&{G@&%+{FLzg1Ctf{!;fkbT8i+<~P%4SKiMjyNY{F@=eAQ4aF8^ zeTCr837Y~Wn*8H3@@00=E6R0tG0+3S1434>lLwmFz4j9IqH(s}qXFu|CCfxK&1|H$ z8clUu_m&|?j+Ea=OQdGrqotZSKv~^(8t2Cg5q{mz!zSZ;;C-x?!hD#|%A;F|qbUKC zRX}UN^7N*r7;;nNIsb9DzvUw;IMu(DgS`3KHI`a?a#ES7z8c8^Tss=I=5nudhQ_v*vq_6! zNtY>^^fmfK%2>i*?QR*!1=Cx$ibv9RCi(>)=1j23v@5GeIQXfu103exqDUl9yG-O~ z_lS4;<*`F_)S8-&mVQ_ln@y{?X)t3wh8SIG>h}8E;2`(EP!2xt)2vw5Fh}XkT5&hX zEuFccosm~+xU87F;gs*n-GFndS-Foy`Z)$?Xn#yNnPbgo<(8dTZEWpi(9_%oM_Ju< zGZhs;B!$X=y?R|xU{>}9Z@ClIP#FkhbYA<1ep z_PyU6u523FI^2lvY-}1EBB|EBYqxW5(qiitbaRjLMc~9gum$c53YGXs&MWP~vA4xC zbO^?W?SCBP0Mnq~Dq|fI#}`lc-Rvjb=Bsej7W@E0UPX@3@@!2XxhZj7&l5TrJ;J8v z2C7d;{&qP-EO^&sY#LEbEeKzyKTCHUkJw?OSbGquEpGWY8lmD{lc`}b#p?qAJJ@aN zE?=m3NG(CUKY`C@3ITx!a7;)jCJJ$7BxCWoRGQ&h0%8R*D~r2NvG% zBHhKI?HF^;Ws!t3DIFLKw-hqbmS*}T=U3qqj}#xSLNXsZc~=2G0Tp2|-~~-$t?{w1 zAO39S(S?V@o4`Oo-Jn1~r2lB@!8>?A)6kpo}RvEOW1skrc^MP^+ zh>$H9!LigR=)lcS%8vtbElW+sh3sF*Kwp!TW`a45*yg39s-$=^r!`MN<9w_k_mZVrwXL=PGY#>bT?w|!2oc4iQ6`8r{TM} z7a}N(j`?e`u=F^7J@;+s4oml37D%JMvss_p_lJOE+j*c+jRY#BK9Q((@Rv2V2x1mz zz``I?oww?Y%JK!ztsJAwPsn~x;h8`xFXp6bn}N>H?`c4O;c0Lo-6B)a%;Jy&xgt}J zPNjNMp8j51nl`!Y4l?9FR_hI(5lw}~wqMs{|13P>e#|U@B1Oe;&|0E=e)oY$T%!L; z_}ocp)UBA)!rH8YwS~=`5pG#QwXAwrD>ODE1U8irIY)_7U3qQYJU8jL#UMTNp~t=e6QgV6nd)LPQNd%*Z8vq?04x zYH$gWzr@(4xLhw&%P5sK58ce4^CG$?6L7&nANOM69d- z<_UY=^1uxLY$9*gp=RN1E+AxQ>*Va{V&rV+_%CZoQnIm|d9xNeT9o!tvOr3w$(FJn z-DBqrF38WuWF-AQ{EYoS^PH2C64@wCy2t7cqeL5~UMP0j(C6~JF>KB`Iqx%Xc&6Gq zpRaDl+<>?#`U#9=2DsQz3Q>9F86#zE@vg@UDE5`FiM~e=jXb-eP@cP?@R;hGgzRRo zTy)h10vrdNyaG1ZL8r{Vl~-H+LLEB%QHcl8oVZ!>Jm6>N-IxKbKtKFyXQJqo?VmGS z{;l3Z1v4>8wC&EbX0rChm8)<#e(Sakgf}6pUZvU{0u5k2;aZjQY&&+Xhe;diiW1QF znw^(e<`P9LOb_g`5}@6SYYF7;9xL-w+f(Er;T~$J}Bb{`!eU)i0rvt+J2S zFqemquO254GF-QOxQZ@|=u5&ULC%*zMD#YZAeBDY(eApSPU`(Oa?16qSSbi-0)3Bb+D^p_J~4Yoz!9;e^t8>h_FSuo|sSo%n@O|NB;L< z7NQ9v@+T^!{LhG0F=Iuy?+OFI?b~8q>{^j;)~furZ!`a|)~f7g_s(9O{xDb_rCE6d z-jqTaY{TA}&mukabIp*zU{B^}@-Q*;&>ux`2CoQ%)cb;r$z-nVBrpf2r?-~y_ge3f zsLkK@MK|^gUa!gXiHYAga&}-;tE@<*J#{RTklJ%>=oFjWK4J81c8e7>OD1_f~7`^IjiiAZ}+awvp2N7 zwdnzqQsnfd^a#&Nny8v=RaAjYZ5q{`x>d~MU1w=Dp86cL>qFjbi(XCISFSW60qJL& zR#ne7V;c<3xSj=&%Rla6ldNr~I2fFV?6Ez0FKt>BhJVl`R(cd~Sz~og{1QT3V!az7 zeMR1MLbX|hmxKlA+*Y*7l*7B)q;u=GU{@nHdK-SJ=V6?w+HNGF)~+QIl=RKC!eY^OP8{Yfd4*o>nrg!<{H2@8*?fIz%KJGm_!vU~m(8W}6BkuZQDgr%@m z!YGW;q01>G?8u$2DQP#xi)1^FimsVQ3_c znY$U#FXhA8Ri*6Z4rY5=9+z2Yb4b<>L;Qy;_VpGH(`59qR+y&+#-q@vb)KvA*ve@jq#=U0l2Qss;Ji$ zBy}^0S$(`)CGjYbqV-O#Uo(Hf{n-^pCbJZ*5>};`}dD4ptQz zM^-?1Np9|Ve5L8)2-rq(YY~jJY5|X+Hwhr3wQgzcc)Pr65s(D?z$IFdT6+ROw**@W zm}??e$b1^?OuOuMCsuB^O0eC4ScZyt+!?v?ofy=55x{S5rg351HHMQ#zS1PG@Z!4v zatOc-zP4x~`6yK|DFMfo-!AVSST%UJq~#mP~->&4b!(hcp8dbg{hiXkvU<&X0Sg!>)n)kq|Lao~8 z8E%{-oXCFC;b*dR%CY!d7r7#ujvHa-ggPc9syoRQBkU;rHG=r&st++q4p>1-OA_;r z=QboiKLkDY!+zP)Cs~&H+~UR{s8u9ZsdsPAAvi9|fE9V0m!eKWp`G+;%XeBmhk;X$ zi5W#0I)0u_jJ)CN5mlc2fiu-kDy5k}C!-Z&{<6P*je2TrQpgiMp$C;wSgB)Gk6%`2 z)@(s|w|I^5=y5_8%V>SUerY(4LhUUsah^k!?#@J+Dd^`Y8+{H}Ce~(|O~0=LUPZ|J z{lLXp##|}08BFBy6ffBLW@~I|l3Zt`iNAze&-3K#^4?x2vs3G?iFP@B(G(7(#H^_eUUF;h}+m< zYG6t8miD4)OUAe^8HdpK=Z`=~Ojww;hF0sb8|2SHw6cPUF$zW^K>yhWISe@MVr=^l6R zP*$8?1*~-SK^&{5JLV3)(CZdd)R??BSmt&)HrJ6`z`tFO;E7i}}>0uI?s~&LZ_VLU(1$hw6cUwjH z^v@pQmxh-}B6eJtIoJ|6ajB`Y3X!*(0lM9yd2Go~P26;qOR+-a=e`+yaL-fIVKs9( zAxW{VhaZnIF^BRo@Wz@c191q_Y`?{R#qCokV@~=Rm~Ojeye=b+c>XcIKdZKwd_eyd zi!E_7LQ2iP-omVM^_-rCP?9doxkqXFT$={51s^L zOxX@9l3yd;kVjO|tHB36XCzU%Drjs;Phx$}&lyPQRyUDeR(hcqbYD;PHpyQVwB;sY zprTB<<>;&W`RjP)Ii{9fsI&vMx$VIv&zQQX<>_}*h2eCo{V~S!2u2Gqs32AO43@Z( zsb5qZ4z%V!MIqxzJPa_bPqYPOG}PRgP#pM5v}}JodPr6O4)KCm`2t;ii=CPSwb65? z-HpU`&G8eAY-=Ovwnlm0FPG{nDWV&gP6gXtBu{c;Sxv#dujbO~Tdby|DDerfpg2^Dzd*?^|QGt9(p++|tLg z_a!BY3cV42j6FzFMQc@{E9AGHcSL`2kkgnC^BOA;sGxAcEsCz7V79L#!hL)Snwlkc ztRy5_D9}DBV8Hrj!J0p7BR#tqkaRublX#w4$I(o)x8BG$Lk@D;-+JDbF(R*u1QuNxliS z+*Jf>NmooP?}WrTD-wyNupsiA3w8NAS=9j%l>#??emmm*G$)3`FCr`~hdrWnYzIp( zEn?k7I?@cqNHr`A#*ErzRH768Od@-uE9MzSuGl+IN`& za*}P-+CvxIGqX=(Uy8smk*!Y~(MuqyY( zjwZ%I+Wg)adz<0MMj!{?c6`9lhinFn0Qm}81&02aHf>vDTIUG|k?I(8ww)!yVihAI z^~GX&4+{r1;=a9?TXElv3rD4Ri)_ttc?NLr_S9*u@ojE!iH1w3L_PHk*v(+u$IC+NX^ODxAg{qh6lS!luRRRv^GEI-j$*=&fCn0TDG9%+9wZ-z zYsK?KDcJDL11P?eYXSu2#)~1ZD#sw5+F{-m)Lwmz)H2!;k$?&>QU~}asTXTG6H!ab z`c)U0n3)W1Q;haRwvd2_R*W^7MuAsD8D)@0P!?BVBl7m!Qad<8%^w56F2EBl)BGR5 zaeD$a=e!0CP7ARB^G$pEfB%%nZ^~?dH7#{hs7tbLx*dgR^(Ffgt{kL|9>67H`VQ`P z)?JAjB!k^N>r)6u*!85S2e+u-n?~IHW5AmCBeU`&$Q5salY^S$x@d%Gx=Jf1WxG=E z#()>r&aQ?q9;ad)Sx4|GqNmvFyRR(btsKXz;FHks7Ke9Y{6hoUyJB2cDwH&i%3Cq6 zWpSJihQ@8onpRa=QUI*cGQd*GMx<{3^PFalfg7|^GVUsFr8~a+#yzG$)dKapW~_O% z=ni5{s(JoZL^xJ#>9jlb%f?FDl0nKsfwAej*UkE)@9Txng;#^mUJZE;VScc)McDpK zI{~hQ*od=pSWKRgiK5AIibc4z6luf=N{V=bg-;l?x&J*zq6GcG;T8h8MV7Qg8f=k`C>wQTWWlZtuH>YUJ2qN2CCbMgw5We zeRuM)$|JHl( z{7HNU7{pcPC-;Q95M%wkFstrBzX3vO8c;xQn!)=e}r7RLw$*O~CDPTxSbh@nrJ z+5>!q26K0qinotjWPbFugcded8;|3eFA^=?i!KW%Ol&Jl3A>Dpn)rvGAV2}Dd9odw!ss5oKm2<1uCxjL6oW64KBz za+&H9*r2 zA2%Q2C^)tmB2tC-r5|&(@3z9cU zY)!Lf&P7s0K7ogf$gnzCGGg~(2C|0q3x?X_S^A9d4bYua*krNOCO~^?zJG2yK)^`> z4sZ=uA;hz3Sl%Ye4x!NJNFoC^b?&kv1$J`-cMUto*)5mv)TTsltekO{Paex2!ct*2 zxa!DiibV;wIsmz23&6k{C=c!UB0)Q!CO>O|*R#k8yTr+K;^vN$T|^o6NURs(h;mdnq>2(I88vz_74xi#boh*Sd1xIt#p5t>O71Fubn-8W z+qh)kOIghJCv9`z{;X@L#0q?dNR;B#)!@N_^C^Dwobwx z$jdG%snoTw)&+yLlEiP{hg!>J}gNz;*OrmxRIP zj3oH%zuyZj!JsAh0!Jw#G1Zi=8Kqv@_x&<)U{uB>}i3sGU;O7(DyA{Y_MFt!p4~Zi zIR*POG^!;_h;RU?l)!37?H33`WM{w$H6n2Z0&yr2ohqO$v^UR(u4^9_-}54U4BgO4 zer;&0%@44?xI=n-d-VAMoljpVUdqBXMf6 zX={0P^x0=)Y-v1@!P(?|CNd;NaD2Z2C}=|L7kgWQi@?yBq0m4bI6jj&-shH6UT^ASmGU$AJYRZRhIt4lm zUaAB3H8Q{#D$|=1h)#$^7yc_XLYbPOlAcK95!Pv$m5!n+ha#6XW&S?8Y>Ek8F#xe) z0BJT2HGzJ&;|$7!TW?s9s{i=|WE)}#d1)e9-IAR^Uni=@3ES-wSpUk_33pryo6yg- z#>8`n@IzbQu3@8>~^4DW1Hlj$`j#?qgj#nmzr>>1f zCDY=r(~+Rm;r6}~GUtPc#IK(3G)aCsS|fQmBb}5*YA$Hy@I$^(HbERmYCyT%wyr4i zOfPw`Ks&z=cm*!?0?YP9`Q-yc^uvMX2b%CPvifleLY17+bavkJp$5&pleo?lu}!Cc zc<;yR-130VCGqaZYw0Q8y~1_w`j-JLRQuN# z0g+R7sv8tBXse>QAlXOGD@UYkZQG*mwT*zCW(_ALzC5j#`B6)9nfa0V0w%AtAuF*JlNGKO>9PwrPW7p^k zn`|Z4Nrnc8Nab#e#ur5gLBEi5y-k8gq`R(WzJPD4gu4lkyOe=hCNWtB4X))`1kg8e z1bD)22Wu^dFT8Uv{wy!V%f1h0T8~qOWmvPX3B`KT&u-=q$gagNOOw~HW#JwS0kOtt zxsVB^U%+2`(R3^AyU67lk)#8EW;eR-T6bNIHgw1!fpmW#3?+pDxFb#&4m2WD7lGHt zO`yO{qRR+PhMKUBLU7>3YT_`40@wxMG7Hr0!IHvQ1fZGLz*H#WH%Xd^mShwQkSJ3N zbx^<3C`%p|#fy)Tr5AzO5^Kb>wO!$_qWO|uUKRD4&LYxCK3m7Y@a=C7731;%x8;{p z49{vW-jPTrh7pbdg1nV`)% zvc{nASznV9NmeIB?Fn9!6e$KwDl~T&6)R%o5q+G&xSz^cn6D7$*gD_93VEWJtk29| z{xnOkHs|zus`Y?GxEbs=E7cJbwH{S@5FY540KtW;4JBzqQ6@bCEEHw_IRq~N9 zH$wfd{4w2e%abV0L?_X+QQmOb`28V@_B1MwIuR5Y_qrtX5gdF|P)I1z&SA*Af?37_J2M()8R=OkNX>C{-kPyP$Kclo~MjPl;I!XbC*=6Nf?{ zYYFVhl!XlHDx;2>VqJ$q8JmfCHZkExonKVwMiW=B9P(wLc92xa@@YY%h^0L6RI~CH zf_qo;ZHQDux!1xG4N8=~vQA~u6QykZEkZR71@v{U&IMJ;Vv0>w31W!g9arl9dXYJ1 z7FRjN;$KH^^$<>_f5(PieX$veriGbU$G?IAfe7s7X1e=F|x1 z0N4!bXdN4pT9=BuoP3j&6k2q2Yv)MgwSh5gJ$Ht#H0Kf^#p1WG#j2!Q?}#a0$<&08N91*#eGSxzV2B%ljL! zrf7OskF*p&rFOsog>nP6gVzet0XcpiW9{?hOp@UnS>mnrS-eK!WBT@9ElCPxm?G0;E+ zzdr#3VF1C5=t0Y0%>nEk`DPI%7muq@k#|6nMPK)=EMxpm+@EDYK|!v13;!FvtJGIRf=!5^CZb*2AY4t}pe z+uOnYA71?58vJc>_`MQ;81oKI=oBIyhk%+j34^#3;u(0PR0EGEH4HAmQDo%f`9u%c)NrDt+xQ^{{S$< B78L*h literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jdk-9.0.1.zip b/src/test/resources/zip/data-java-jdk-9.0.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..f062b95e58375a526d5249b2cdd578659799ecc4 GIT binary patch literal 14630 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/zip/data-java-jrockit-90_150_06.zip b/src/test/resources/zip/data-java-jrockit-90_150_06.zip new file mode 100644 index 0000000000000000000000000000000000000000..8cad4c32699132275dc9b6a1d535257ffed101ef GIT binary patch literal 37907 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